Source code for artv2_utilities.component_utilities

# -*- coding: utf-8 -*-
"""

This module contains functions for returning information specific to components or functions that operate specifically
on components.


Functions
---------

- :func:`check_for_children <artv2_utilities.component_utilities.check_for_children>`
- :func:`find_associated_mover_from_joint <artv2_utilities.component_utilities.find_associated_mover_from_joint>`
- :func:`get_all_created_joints <artv2_utilities.component_utilities.get_all_created_joints>`
- :func:`get_all_rig_asset_nodes <artv2_utilities.component_utilities.get_all_rig_asset_nodes>`
- :func:`get_component_instance <artv2_utilities.component_utilities.get_component_instance>`
- :func:`get_rig_asset_node <artv2_utilities.component_utilities.get_rig_asset_node>`
- :func:`get_top_level_mover <artv2_utilities.component_utilities.get_top_level_mover>`
- :func:`return_all_components <artv2_utilities.component_utilities.return_all_components>`
- :func:`setup_global_scale <artv2_utilities.component_utilities.setup_global_scale>`
- :func:`validate_asset_name <artv2_utilities.component_utilities.validate_asset_name>`
- :func:`validate_prefix <artv2_utilities.component_utilities.validate_prefix>`
- :func:`validate_suffix <artv2_utilities.component_utilities.validate_suffix>`

"""

import re

import pymel.core as pm

import error_utilities as errors


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def get_rig_asset_node(): """ Returns the network node for the entire rig asset. If more than one asset node exists, an exception will be raised. :return: Network node name (str) that represents the entire asset. """ metanodes = pm.ls(type="network") character_nodes = [] for metanode in metanodes: if metanode.hasAttr("components"): character_nodes.append(metanode) if len(character_nodes) == 1: return character_nodes[0] else: if len(character_nodes) == 0: raise StandardError("No character nodes exist.") else: raise StandardError("More than one character node exists in the scene.")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def get_all_rig_asset_nodes(): """ Returns all rig asset (character) nodes. :return: A list (str) of all rig asset network node names. """ metanodes = pm.ls(type="network") character_nodes = [] for metanode in metanodes: if metanode.hasAttr("components"): character_nodes.append(metanode) return character_nodes
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def return_all_components(): """ Returns all network nodes belonging to components. :return: A list (str) of all rig module network node names. """ metanodes = pm.ls(type="network") components = [] for metanode in metanodes: if metanode.hasAttr("asset"): if metanode.asset.connections() is not None: components.append(metanode) return components
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def get_top_level_mover(node): """ Gets the top-most global mover of a module. :param node: PyNode of the mover group for the module. :type node: pymel.core.PyNode :return: Returns the name of the top-most global joint mover of the module. """ return node.childAtIndex(0)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def find_associated_mover_from_joint(joint_name): """ Gets the name of the joint mover (global, but offset if global doesn't exist) that corresponds to the given name. :param joint_name: The name of the joint whose corresponding mover to search for. :type joint_name: str :return: The name of the joint mover that corresponds to the joint name. :rtype: str """ network_nodes = return_all_components() for node in network_nodes: module_inst = get_component_instance(node) movers = module_inst.joint_mover.get_movers() offset_movers = movers.get("offset") for offset in offset_movers: mover_joint = offset.created_joint.get() if mover_joint == joint_name: del module_inst if pm.objExists(offset.name().rpartition("_offset")[0]): return pm.PyNode(offset.name().rpartition("_offset")[0]) else: return offset del module_inst return None
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def get_all_created_joints(): """ Get all created joints from all components. :return: Returns a list of all joints that components will or have created. :rtype: str, [] """ joints = [] network_nodes = return_all_components() for node in network_nodes: inst = get_component_instance(node) joints.extend(inst.joint_mover.get_created_joints()) del inst return joints
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def check_for_children(joint): """ Checks if the given joint has any child components that are using it as their parent. :param joint: Name of joint to check. :type joint: str :return: Returns a list of components that were children of the joint. :rtype: str, [] """ child_components = [] components = return_all_components() for component in components: if component.parentComponentBone.get() == joint: child_components.append(component) return child_components
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def validate_prefix(metanode, prefix): """ Ensures that the given prefix is a valid name for Maya, as well as ensuring it has a trailing underscore. Also ensures that no other module exists with the new name, factoring in the adjusted prefix. :param metanode: The rig module's network node name. :param prefix: The prefix to validate. :return: Returns a valid prefix as a string. If the prefix was invalid, returns False """ if prefix is not None: if len(prefix) > 0: if not prefix.endswith("_"): prefix += "_" else: prefix = "" if re.search('^\d', prefix): errors.raise_error("Name cannot start with digits!") return False if re.search('\W', prefix): errors.raise_error("Name has non-alphanumeric characters!") return False if metanode is not None: old_prefix = metanode.prefix.get() base_name = metanode.baseName.get() suffix = metanode.suffix.get() components = return_all_components() if not prefix == old_prefix: for each in components: if each.prefix.get() == prefix: if each.componentName.get() == prefix + base_name + suffix: if each != metanode: errors.raise_error("A module with this name already exists!") return False return prefix
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def validate_suffix(metanode, suffix): """ Ensures that the given suffix is a valid name for Maya, as well as ensuring it has a leading underscore. Also ensures that no other module exists with the new name, factoring in the adjusted suffix. :param metanode: The rig module's network node name. :param suffix: The suffix to validate. :return: Returns a valid suffix as a string. If the suffix was invalid, returns False """ if suffix is not None: if len(suffix) > 0: if not suffix.startswith("_"): suffix = "_" + suffix else: suffix = "" if re.search('^\d', suffix): errors.raise_error("Name cannot start with digits!") return False if re.search('\W', suffix): errors.raise_error("Name has non-alphanumeric characters!") return False if metanode is not None: old_suffix = metanode.suffix.get() base_name = metanode.baseName.get() prefix = metanode.prefix.get() components = return_all_components() if not suffix == old_suffix: for each in components: if each.suffix.get() == suffix: if each.componentName.get() == prefix + base_name + suffix: if each != metanode: errors.raise_error("A module with this name already exists!") return False return suffix
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def validate_asset_name(name): """ Ensures that the given name is a valid name for Maya. :param str name: The name to validate. :return: Returns True if name is valid, otherwise False. """ if re.search('^\d', name): errors.raise_error("Name cannot start with digits!") return False if re.search('\W', name): errors.raise_error("Name has non-alphanumeric characters!") return False return True
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
[docs]def setup_global_scale(mover): """ Sets up an aliasAttr so that only uniform scale is possible. :param mover: Name of the node to setup the uniform scale. :type mover: str """ if mover.hasAttr("globalScale"): pm.aliasAttr("globalScale", mover.scaleZ) mover.globalScale.connect(mover.scaleX) mover.globalScale.connect(mover.scaleY) mover.scaleX.set(keyable=False) mover.scaleY.set(keyable=False)
[docs]def get_component_instance(network_node): """ Given a network node for a module, create an instance of the module and return it. :param network_node: The name of the network node to gather the necessary information from to create an inst. :type network_node: str :return: Module instance :rtype: class.instance """ path = network_node.modulePath.get() class_name = network_node.className.get() module_name = path.rpartition(".")[2] mod = __import__(path, {}, {}, [module_name]) module_class = getattr(mod, class_name) module_inst = module_class(network_node=network_node) return module_inst