# -*- 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