Skip to content

Commit

Permalink
Merge pull request #190 from TrevisanGMW/dev-feature/unittests
Browse files Browse the repository at this point in the history
Created a few missing unittests
  • Loading branch information
TrevisanGMW authored Sep 22, 2023
2 parents d383c2e + 43a3b88 commit 767666f
Show file tree
Hide file tree
Showing 46 changed files with 1,130 additions and 438 deletions.
2 changes: 1 addition & 1 deletion gt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys

# Package Variables
__version_tuple__ = (3, 2, 0)
__version_tuple__ = (3, 2, 1)
__version_suffix__ = ''
__version__ = '.'.join(str(n) for n in __version_tuple__) + __version_suffix__
__authors__ = ['Guilherme Trevisan']
Expand Down
155 changes: 96 additions & 59 deletions gt/utils/cleanup_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,74 @@
logger.setLevel(logging.INFO)


def delete_unused_nodes():
def delete_unused_nodes(verbose=True):
"""
Deleted unused nodes (such as materials not connected to anything or nodes without any connections)
This is done through a Maya MEL function "MLdeleteUnused()" but it's called here again for better feedback.
Args:
verbose (bool, optional): If True, it will print feedback with the number of unused deleted nodes.
Returns:
int: Number of unused deleted nodes.
"""
num_deleted_nodes = mel.eval('MLdeleteUnused();')
feedback = FeedbackMessage(quantity=num_deleted_nodes,
singular='unused node was',
plural='unused nodes were',
conclusion='deleted.',
zero_overwrite_message='No unused nodes found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=num_deleted_nodes,
singular='unused node was',
plural='unused nodes were',
conclusion='deleted.',
zero_overwrite_message='No unused nodes found in this scene.')
feedback.print_inview_message()
return num_deleted_nodes


def delete_nucleus_nodes():
""" Deletes all elements related to particles """
def delete_nucleus_nodes(verbose=True, include_fields=True):
"""
Deletes all elements related to particles.
Args:
verbose (bool, optional): If True, it will print feedback with the number of deleted nodes.
include_fields (bool, optional): If True, it will also count field as "nucleus nodes" to be deleted.
Returns:
int: Number of nucleus deleted nodes.
"""
errors = ''
function_name = 'Delete Nucleus Nodes'
deleted_counter = 0
try:
cmds.undoInfo(openChunk=True, chunkName=function_name)

# Without Transform
emitters = cmds.ls(typ='pointEmitter')
solvers = cmds.ls(typ='nucleus')
instancers = cmds.ls(typ='instancer')

no_transforms = emitters + instancers + solvers + instancers
# Without Transform Types
no_transform_types = ['nucleus',
'pointEmitter',
'instancer']
# Fields/Solvers Types
if include_fields:
field_types = ['airField',
'dragField',
'newtonField',
'radialField',
'turbulenceField',
'uniformField',
'vortexField',
'volumeAxisField']
no_transform_types += field_types
no_transforms = []
for node_type in no_transform_types:
no_transforms += cmds.ls(typ=node_type) or []

# With Transform
nparticle_nodes = cmds.ls(typ='nParticle')
spring_nodes = cmds.ls(typ='spring')
particle_nodes = cmds.ls(typ='particle')
nrigid_nodes = cmds.ls(typ='nRigid')
ncloth_nodes = cmds.ls(typ='nCloth')
pfxhair_nodes = cmds.ls(typ='pfxHair')
hair_nodes = cmds.ls(typ='hairSystem')
nconstraint_nodes = cmds.ls(typ='dynamicConstraint')

transforms = nparticle_nodes + spring_nodes + particle_nodes + nrigid_nodes
transforms += ncloth_nodes + pfxhair_nodes + hair_nodes + nconstraint_nodes

# Fields/Solvers Types
# airField
# dragField
# newtonField
# radialField
# turbulenceField
# uniformField
# vortexField
# volumeAxisField

deleted_counter = 0
for obj in transforms:
with_transform_types = ['nParticle',
'spring',
'particle',
'nRigid',
'nCloth',
'pfxHair',
'hairSystem',
'dynamicConstraint']
with_transforms = []
for transform_node_type in with_transform_types:
with_transforms += cmds.ls(typ=transform_node_type) or []

for obj in with_transforms:
try:
parent = cmds.listRelatives(obj, parent=True) or []
cmds.delete(parent[0])
Expand All @@ -78,13 +93,13 @@ def delete_nucleus_nodes():
deleted_counter += 1
except Exception as e:
logger.debug(str(e))

feedback = FeedbackMessage(quantity=deleted_counter,
singular='object was',
plural='objects were',
conclusion='deleted.',
zero_overwrite_message='No nucleus nodes found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=deleted_counter,
singular='object was',
plural='objects were',
conclusion='deleted.',
zero_overwrite_message='No nucleus nodes found in this scene.')
feedback.print_inview_message()

except Exception as e:
errors += str(e) + '\n'
Expand All @@ -94,32 +109,50 @@ def delete_nucleus_nodes():
if errors != '':
print('######## Errors: ########')
print(errors)
return deleted_counter


def delete_all_locators():
""" Deletes all locators """
def delete_locators(verbose=True, filter_str=None):
"""
Deletes all locators
Args:
verbose (bool, optional): If True, it will print feedback when executing operation.
filter_str (str, optional): If provided, it will be used to filter locators.
Only locators containing this string will be deleted.
Returns:
int: Number of deleted locators
"""
errors = ''
function_name = 'Delete All Locators'
function_name = 'Delete Locators'
deleted_counter = 0
try:
cmds.undoInfo(openChunk=True, chunkName=function_name)

# With Transform
locators = cmds.ls(typ='locator')

deleted_counter = 0
for obj in locators:
filtered_locators = []
if filter_str and isinstance(filter_str, str):
for loc in locators:
if filter_str in loc:
filtered_locators.append(loc)
else:
filtered_locators = locators

for obj in filtered_locators:
try:
parent = cmds.listRelatives(obj, parent=True) or []
cmds.delete(parent[0])
loc_transform = cmds.listRelatives(obj, parent=True) or []
cmds.delete(loc_transform[0])
deleted_counter += 1
except Exception as e:
logger.debug(str(e))
feedback = FeedbackMessage(quantity=deleted_counter,
singular='locator was',
plural='locators were',
conclusion='deleted.',
zero_overwrite_message='No locators found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=deleted_counter,
singular='locator was',
plural='locators were',
conclusion='deleted.',
zero_overwrite_message='No locators found in this scene.')
feedback.print_inview_message()

except Exception as e:
errors += str(e) + '\n'
Expand All @@ -129,4 +162,8 @@ def delete_all_locators():
if errors != '':
print('######## Errors: ########')
print(errors)
return deleted_counter


if __name__ == "__main__":
logger.setLevel(logging.DEBUG)
34 changes: 17 additions & 17 deletions gt/utils/color_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self):
"""
Constant tuple RGB values used for element colors.
"""
CENTER = (1, 1, 0.65)
LEFT = (0, 0.5, 1)
RIGHT = (1, 0.5, 0.5)

Expand Down Expand Up @@ -61,16 +62,19 @@ def set_color_override_outliner(obj, rgb_color=(1, 1, 1)):


def add_side_color_setup(obj, color_attr_name="autoColor",
left_clr=ColorConstants.LEFT, right_clr=ColorConstants.RIGHT):
clr_default=ColorConstants.CENTER,
clr_left=ColorConstants.LEFT,
clr_right=ColorConstants.RIGHT):
"""
This function sets up a side color setup for the specified object in the Maya scene.
It creates connections and attributes to control the color of the object based on its position in the scene.
Parameters:
obj (str): The name of the object to set up the color for.
color_attr_name (str, optional): Name of the attribute used to determine if auto color is active or not.
left_clr (tuple, optional): The RGB color values for the left side of the object. Default is (0, 0.5, 1).
right_clr (tuple, optional): The RGB color values for the right side of the object. Default is (1, 0.5, 0.5).
clr_default (tuple, optional): The RGB color for when the object is in the center or not automatically defined.
clr_left (tuple, optional): The RGB color for when on the left side. e.g. (0, 0.5, 1).
clr_right (tuple, optional): The RGB color for when on the right side. e.g.(1, 0.5, 0.5).
Example:
# Example usage in Maya Python script editor:
Expand All @@ -80,7 +84,6 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
return

# Setup Base Connections
default_clr = (1, 1, 0.65)
cmds.setAttr(obj + ".overrideEnabled", 1)
cmds.setAttr(obj + ".overrideRGBColors", 1)
clr_side_condition = cmds.createNode("condition", name=obj + "_clr_side_condition")
Expand All @@ -103,34 +106,31 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
# Setup Color Attributes
clr_attr = "colorDefault"
add_attr_double_three(obj, clr_attr, keyable=False)
cmds.setAttr(f'{obj}.{clr_attr}R', default_clr[0])
cmds.setAttr(f'{obj}.{clr_attr}G', default_clr[1])
cmds.setAttr(f'{obj}.{clr_attr}B', default_clr[2])
cmds.setAttr(f'{obj}.{clr_attr}R', clr_default[0])
cmds.setAttr(f'{obj}.{clr_attr}G', clr_default[1])
cmds.setAttr(f'{obj}.{clr_attr}B', clr_default[2])
cmds.connectAttr(f'{obj}.{clr_attr}R', clr_center_condition + ".colorIfTrueR")
cmds.connectAttr(f'{obj}.{clr_attr}G', clr_center_condition + ".colorIfTrueG")
cmds.connectAttr(f'{obj}.{clr_attr}B', clr_center_condition + ".colorIfTrueB")
cmds.connectAttr(f'{obj}.{clr_attr}', clr_auto_blend + ".color2") # Blend node input
r_clr_attr = "colorRight"
add_attr_double_three(obj, r_clr_attr, keyable=False)
cmds.setAttr(obj + "." + r_clr_attr + "R", left_clr[0])
cmds.setAttr(obj + "." + r_clr_attr + "G", left_clr[1])
cmds.setAttr(obj + "." + r_clr_attr + "B", left_clr[2])
cmds.setAttr(obj + "." + r_clr_attr + "R", clr_left[0])
cmds.setAttr(obj + "." + r_clr_attr + "G", clr_left[1])
cmds.setAttr(obj + "." + r_clr_attr + "B", clr_left[2])
cmds.connectAttr(obj + "." + r_clr_attr + "R", clr_side_condition + ".colorIfTrueR")
cmds.connectAttr(obj + "." + r_clr_attr + "G", clr_side_condition + ".colorIfTrueG")
cmds.connectAttr(obj + "." + r_clr_attr + "B", clr_side_condition + ".colorIfTrueB")
l_clr_attr = "colorLeft"
add_attr_double_three(obj, l_clr_attr, keyable=False)
cmds.setAttr(obj + "." + l_clr_attr + "R", right_clr[0])
cmds.setAttr(obj + "." + l_clr_attr + "G", right_clr[1])
cmds.setAttr(obj + "." + l_clr_attr + "B", right_clr[2])
cmds.setAttr(obj + "." + l_clr_attr + "R", clr_right[0])
cmds.setAttr(obj + "." + l_clr_attr + "G", clr_right[1])
cmds.setAttr(obj + "." + l_clr_attr + "B", clr_right[2])
cmds.connectAttr(obj + "." + l_clr_attr + "R", clr_side_condition + ".colorIfFalseR")
cmds.connectAttr(obj + "." + l_clr_attr + "G", clr_side_condition + ".colorIfFalseG")
cmds.connectAttr(obj + "." + l_clr_attr + "B", clr_side_condition + ".colorIfFalseB")


if __name__ == "__main__":
logger.setLevel(logging.DEBUG)
from pprint import pprint
out = None
pprint(out)

add_side_color_setup("pSphere1")
3 changes: 2 additions & 1 deletion gt/utils/data/controls/cluster_driven.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def create_scalable_one_side_arrow(name='scalable_one_side_arrow', initial_scale


def create_scalable_two_sides_arrow(name='scalable_two_sides_arrow', initial_scale=1,
min_scale_apply=False, min_scale=0.01):
min_scale_apply=False, min_scale=0.01):
"""
Creates a curve in the shape of an arrow and rigs it so when scaling it up the curve doesn't lose its shape.
Instead, it scales only in the direction of the arrow heads. Use the "<name>_scaleCtrl" to determine the scale.
Expand Down Expand Up @@ -197,3 +197,4 @@ def create_scalable_two_sides_arrow(name='scalable_two_sides_arrow', initial_sca
logger.setLevel(logging.DEBUG)
cmds.file(new=True, force=True)
create_scalable_one_side_arrow()

Loading

0 comments on commit 767666f

Please sign in to comment.