Skip to content

Commit

Permalink
Fixed parenting in AbstractGrouping to work with the built in parent …
Browse files Browse the repository at this point in the history
…method instead of going direct to the dcc.

Made the error in Hierarchy._traverse_up_linear_tree more verbose for node filter.

Fixed build_blend_chain so it uses a duplicate flag and is more standardized.

Combined the two IK/FK chain results into one dict.

Added anvil.utils.scene.print_scene_tree.

Fixed up the implementation of TestBuildHand as errors in the Hand build process would error the entire test class which would screw up the tests.  So now worked it in as a setUp instead.  Also added the Hand test properties to the Base class.
  • Loading branch information
AndresMWeber committed Feb 8, 2018
1 parent c208ec3 commit aa1e556
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 33 deletions.
2 changes: 1 addition & 1 deletion anvil/grouping/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def initialize_sub_rig_attributes(self, controller=None, attr_dict=None):
def parent(self, new_parent):
nodes_exist = [rt.dcc.scene.exists(node) if node != None else False for node in [self.root, new_parent]]
if all(nodes_exist or [False]):
rt.dcc.scene.parent(self.root, new_parent)
self.root.parent(new_parent)
return True
else:
self.warning('Parent(%s) -> %r does not exist.', new_parent, self.root)
Expand Down
3 changes: 2 additions & 1 deletion anvil/grouping/traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ def _traverse_up_linear_tree(self, downstream_node, upstream_node, node_filter=N
node_filter = node_filter if node_filter is not None else self.node_filter
all_descendants = self._traverse_down_linear_tree(upstream_node)
if not str(downstream_node) in all_descendants:
raise IndexError('Node %r is a descendant of %s --> %s' % (downstream_node, upstream_node, all_descendants))
raise IndexError('Node %r is not a descendant of %s --> %s (filter=%s)' %
(downstream_node, upstream_node, all_descendants, self.node_filter))

current_node = anvil.factory(downstream_node)
chain_path = [current_node]
Expand Down
34 changes: 17 additions & 17 deletions anvil/sub_rig_templates/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ def build_ik(self, hierarchy, solver=cfg.IK_RP_SOLVER, parent=None, **kwargs):
rt.dcc.scene.parent(handle, parent)
return {cfg.NODE_TYPE: [anvil.factory(handle, **kwargs), anvil.factory(effector, **kwargs)]}

def build_blend_chain(self, layout_joints, source_chains, use_layout=False, **kwargs):
blend_chain = nt.HierarchyChain(layout_joints, duplicate=not use_layout, parent=self.group_joints)
def build_blend_chain(self, layout_joints, source_chains, duplicate=True, **kwargs):
blend_chain = nt.HierarchyChain(layout_joints, duplicate=duplicate, parent=self.group_joints)

for bl, source_chains in zip(blend_chain, zip(*source_chains)):
for bl, source_chain in zip(blend_chain, zip(*source_chains)):
blender = rt.dcc.create.create_node(cfg.BLEND_NODE)
blender.output.connect(bl.rotate)

for index, source_chain in enumerate(source_chains):
source_chain.rotate.connect(blender.attr('color%d' % (index + 1)))
for index, joint in enumerate(source_chain):
joint.rotate.connect(blender.attr('color%d' % (index + 1)))

getattr(self.root, cfg.IKFK_BLEND).connect(blender.blender)
return {cfg.JOINT_TYPE: blend_chain}

def build_ik_chain(self, layout_joints, ik_end_index=-1, solver=cfg.IK_RP_SOLVER, **kwargs):
def build_ik_chain(self, layout_joints, ik_end_index=-1, solver=cfg.IK_RP_SOLVER, duplicate=True, **kwargs):
kwargs = MetaData(kwargs)
ik_chain = nt.HierarchyChain(layout_joints, duplicate=True, parent=self.group_joints)
ik_chain = nt.HierarchyChain(layout_joints, duplicate=duplicate, parent=self.group_joints)
results = self.build_ik(ik_chain, chain_end=ik_chain[ik_end_index], parent=self.group_nodes, **kwargs)
handle, effector = results[cfg.NODE_TYPE]
# register ik handle and ik effector for passing metadata
Expand All @@ -56,23 +56,23 @@ def build_ik_chain(self, layout_joints, ik_end_index=-1, solver=cfg.IK_RP_SOLVER
rt.dcc.connections.translate(controls[0].connection_group, handle)
return {cfg.JOINT_TYPE: ik_chain, cfg.CONTROL_TYPE: controls, cfg.NODE_TYPE: [handle, effector]}

def build_fk_chain(self, chain_start=None, chain_end=None, shape=None, parent=None,
def build_fk_chain(self, chain_start=None, chain_end=None, shape=None, duplicate=True, parent=None,
name_tokens=None, meta_data=None, **kwargs):
chain = nt.HierarchyChain(chain_start, chain_end)
chain = nt.HierarchyChain(chain_start, chain_end, duplicate=duplicate, parent=self.group_joints)

# Ensure there are enough shapes in the shape list to pair with the chain

controls = []
last_node = parent or self.group_controls
for node, shape in zip(chain, self.get_shape_list(len(chain), shape)):
last_node = nt.Control.build(reference_object=node,
shape=shape,
parent=last_node,
name_tokens=self.name_tokens.merge(self.name_tokens, name_tokens, new=True),
meta_data=self.meta_data.merge(self.meta_data, meta_data, new=True),
**kwargs)
rt.dcc.connections.parent(last_node.connection_group, node)
controls.append(last_node)
control = nt.Control.build(reference_object=node,
shape=shape,
parent=last_node,
name_tokens=self.name_tokens.merge(self.name_tokens, name_tokens, new=True),
meta_data=self.meta_data.merge(self.meta_data, meta_data, new=True),
**kwargs)
controls.append(control)
last_node = control.connection_group
return {cfg.CONTROL_TYPE: controls, cfg.JOINT_TYPE: chain}

def build_pole_vector_control(self, joints, ik_handle,
Expand Down
12 changes: 9 additions & 3 deletions anvil/sub_rig_templates/hand.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ class Hand(SubRigTemplate):
def __init__(self, layout_joints, has_ik=True, has_fk=True, has_thumb=True, **kwargs):
""" General class for a hand.
:param layout_joints: anvil.node_types.Hierarchy, hierarchy chain of joints to use.
:param has_thumb: bool or int, if this is true will use the first digit as a thumb, if int uses that index
:param has_fk: bool or int, if this is true will build fk setup
:param has_ik: bool or int, if this is true will build ik setup
:param finger_joints: [nt.HierarchyChain or str]: list joint chains to build the fingers on.
"""
super(Hand, self).__init__(layout_joints=layout_joints, **kwargs)
Expand All @@ -38,12 +41,15 @@ def build(self, parent=None, use_layout=True, solver=None, meta_data=None, **kwa
self.rename()

def build_digit(self, digit_joints, **kwargs):
digit_nodes = {}
if self.has_fk:
fk_results = self.build_fk_chain(digit_joints, shape='pyramid_pin', **kwargs)
digit_nodes[cfg.FK] = self.build_fk_chain(digit_joints, shape='pyramid_pin', **kwargs)
if self.has_ik:
ik_results = self.build_ik_chain(digit_joints, shape='cube', **kwargs)
digit_nodes[cfg.IK] = self.build_ik_chain(digit_joints, shape='cube', **kwargs)
if self.has_fk and self.has_ik:
self.build_blend_chain(digit_joints, [ik_results[cfg.JOINT_TYPE], fk_results[cfg.JOINT_TYPE]], **kwargs)
self.build_blend_chain(digit_joints,
[digit_nodes[cfg.IK][cfg.JOINT_TYPE], digit_nodes[cfg.FK][cfg.JOINT_TYPE]],
**kwargs)

def get_finger_base_names(self):
num_fingers = len(self.layout_joints)
Expand Down
7 changes: 6 additions & 1 deletion anvil/utils/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import anvil.runtime as rt
import anvil.config as cfg
from generic import to_list
from pprint import pprint


def is_exact_type(node, typename):
Expand Down Expand Up @@ -47,7 +48,7 @@ def list_scene_nodes(object_type=cfg.TRANSFORM_TYPE, has_shape=False):

def get_scene_tree():
startup_cams = [rt.dcc.scene.list_relatives(c, parent=True) for c in rt.dcc.scene.list_scene(cameras=True)
if rt.dcc.scene.API.camera(c, q=True, startupCamera=True)]
if rt.dcc.scene.DEFAULT_API.camera(c, q=True, startupCamera=True)]

top_level_transforms = [node for node in rt.dcc.scene.list_scene(assemblies=True)
if node not in startup_cams]
Expand All @@ -70,6 +71,10 @@ def recurse_scene_nodes(nodes, tree=None):
return recurse_scene_nodes(top_level_transforms)


def print_scene_tree():
pprint(get_scene_tree())


def get_node_hierarchy_as_dict(node_or_nodes, tree=None, node_filter=None):
nodes = to_list(node_or_nodes)

Expand Down
30 changes: 21 additions & 9 deletions tests/acceptance/test_build_hand.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from six import iteritems
import anvil.node_types as nt
from anvil.utils.scene import print_scene_tree
from anvil.sub_rig_templates import Hand
from tests.base_test import TestBase, cleanup_nodes
import string


class TestHandBase(TestBase):
name_tokens = {'name': 'hoof', 'purpose': 'mvp'}
HAND_MERC = "test_skeleton_hand.ma"
TEMPLATE_FILES = {"HAND_MERC": HAND_MERC}
HAND_MERC_JOINTS = ['j_pa_r', 'j_ra_r', 'j_ia_r', 'j_ma_r', 'j_ta_r']

@classmethod
Expand Down Expand Up @@ -38,10 +37,17 @@ def from_template_file(cls, template_file, finger_start_joints=None, **kwargs):
class TestBuildHand(TestHandBase):
rig = None

@classmethod
def setUpClass(cls):
super(TestBuildHand, cls).setUpClass()
cls.rig = cls.from_template_file("HAND_MERC", cls.HAND_MERC_JOINTS)
# @classmethod
# def setUpClass(cls):
# super(TestBuildHand, cls).setUpClass()
# cls.rig = cls.from_template_file(cls.HAND_MERC, cls.HAND_MERC_JOINTS)

def setUp(self):
try:
if self.rig is None:
self.rig = self.from_template_file(self.HAND_MERC, self.HAND_MERC_JOINTS)
except IndexError:
print_scene_tree()

def test_build_no_kwargs_no_errors(self):
self.assertIsNotNone(self.rig)
Expand All @@ -50,22 +56,29 @@ def test_number_of_controls(self):
controls = [node for key, node in iteritems(self.rig.hierarchy) if isinstance(node, nt.Control)]
self.assertEqual(len(controls), 0)

def test_number_of_control_top_groups(self):
self.assertEqual(len(self.rig.group_controls.get_children()), 10)

def test_number_of_joint_chains(self):
self.assertEqual(len(self.rig.group_joints.get_children()), 0)
self.assertEqual(len(self.rig.group_joints.get_children()), 15)

def test_number_of_nodes(self):
self.assertEqual(len(self.rig.group_nodes.get_children()), 5)


class TestBuildDefaultHand(TestHandBase):
def test_build_with_parent(self):
with cleanup_nodes():
parent = nt.Transform.build(name='test')
rig_instance = self.from_template_file("HAND_MERC", self.HAND_MERC_JOINTS, parent=parent)
rig_instance = self.from_template_file(self.HAND_MERC, self.HAND_MERC_JOINTS, parent=parent)
self.assertEqual(str(rig_instance.root.get_parent()), str(parent))


class TestGetFingerBaseNames(TestHandBase):
@classmethod
def setUpClass(cls):
super(TestGetFingerBaseNames, cls).setUpClass()
cleanup_nodes()
cls.hand = Hand(cls.HAND_MERC_JOINTS)

def test_default_with_thumb_from_fbx(self):
Expand All @@ -91,7 +104,6 @@ def test_no_thumb_under_5(self):
def test_no_thumb_over_5(self):
self.hand.layout_joints = ['a' * x for x in range(10)]
self.has_thumb = False

self.assertEqual(self.hand.get_finger_base_names(),
['finger' + string.ascii_uppercase[i] for i in range(10)])

Expand Down
6 changes: 5 additions & 1 deletion tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from deepdiff import DeepDiff
from six import iteritems, string_types
from functools import wraps
import anvil.runtime as rt
from pprint import pprint

os.environ['ANVIL_MODE'] = 'TEST'
import anvil
Expand All @@ -26,10 +28,12 @@ class TestBase(unittest2.TestCase):
TPOSE = 'TPOSE'
FOOT = 'FOOT'
EXTERNALA = 'EXTERNALA'
HAND_MERC = "HAND_MERC"
TEMPLATE_FILES = {APOSE: 'test_skeleton_a_pose.ma',
TPOSE: 'test_skeleton_t_pose.ma',
EXTERNALA: 'test_skeleton_externalA.ma',
FOOT: 'test_skeleton_biped_foot.ma'
FOOT: 'test_skeleton_biped_foot.ma',
HAND_MERC: "test_skeleton_hand.ma"
}

@classmethod
Expand Down

0 comments on commit aa1e556

Please sign in to comment.