From 0c1e65a5501c5e530a419b9ee9d470c04786dbd1 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Thu, 16 Aug 2018 11:08:53 +0100 Subject: [PATCH 1/4] Test IK evaluation bug --- .travis.yml | 2 +- run.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48c9007..c9f4dab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,4 +43,4 @@ script: -v $(pwd):/repo --workdir=/repo --entrypoint mayapy - mottosso/maya:${VERSION} run.py + mottosso/maya:${VERSION} -m nose --verbose run.py diff --git a/run.py b/run.py index 2bbc88c..62b9bb7 100644 --- a/run.py +++ b/run.py @@ -1,6 +1,64 @@ +from nose.tools import with_setup, assert_equals, assert_not_equals from maya import standalone, cmds standalone.initialize() -cmds.file(new=True, force=True) -cube, _ = cmds.polyCube(name="testCube") -print(cube) +a = "Root" +b = "Mid" +c = "Tip" + + +def new(): + # Build Scene + # o o + # \ / + # \ / + # o + # + cmds.file(new=True, force=True) + cmds.joint(name=a, position=(0, 0, 20)) + cmds.joint(name=b, position=(0, 0, 0), relative=False) + cmds.joint(name=c, position=(0, 10, -20), relative=False) + handle, eff = cmds.ikHandle( + solver="ikRPsolver", + startJoint=a, + endEffector=c, + ) + + +@with_setup(new) +def test1(): + assert_equals(cmds.getAttr(a + ".rx"), 0.0) + assert_equals(cmds.getAttr(a + ".rx", time=1), 0.0) + + # Move handle + cmds.move(0, 15, -10, "|ikHandle1") + + assert_equals(round(cmds.getAttr(a + ".rx"), 0), -14.0) + + # This is the bug + assert_not_equals(round(cmds.getAttr(a + ".rx", time=1), 0), -14.0) + + +@with_setup(new) +def test2(): + def getAttr(attr, time): + cmds.getAttr(attr, time=time - 1) + return cmds.getAttr(attr, time=time) + + assert_equals(cmds.getAttr(a + ".rx"), 0.0) + assert_equals(cmds.getAttr(a + ".rx", time=1), 0.0) + + # Move handle + cmds.move(0, 15, -10, "|ikHandle1") + + assert_equals(round(cmds.getAttr(a + ".rx"), 0), -14.0) + assert_equals(round(getAttr(a + ".rx", time=1), 0), -14.0) + + # The above call also enables this other node to evaluate properly + # Which means we only need to call the special function once + # per IK node. + assert_equals(round(cmds.getAttr(b + ".rx", time=1), 0), 49.0) + + cmds.move(0, 15, -15, "|ikHandle1") + + assert_equals(round(getAttr(a + ".rx", time=1), 0), -4.0) From 1a3ed16ab61de505f0b89829d969aa2de2a3cfc7 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Thu, 16 Aug 2018 11:43:54 +0100 Subject: [PATCH 2/4] Support Maya 2013 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9f4dab..6f05f44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,4 +43,4 @@ script: -v $(pwd):/repo --workdir=/repo --entrypoint mayapy - mottosso/maya:${VERSION} -m nose --verbose run.py + mottosso/maya:${VERSION} -m nose.__main__ --verbose run.py From c161cf12e05478b9009484efd3b246b9c303df5c Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Thu, 16 Aug 2018 11:57:26 +0100 Subject: [PATCH 3/4] Cosmetics --- run.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/run.py b/run.py index 62b9bb7..0d427b5 100644 --- a/run.py +++ b/run.py @@ -1,12 +1,16 @@ from nose.tools import with_setup, assert_equals, assert_not_equals from maya import standalone, cmds -standalone.initialize() a = "Root" b = "Mid" c = "Tip" +def setup(): + """Called automatically on start-up""" + standalone.initialize() + + def new(): # Build Scene # o o @@ -26,7 +30,9 @@ def new(): @with_setup(new) -def test1(): +def test_bug(): + """Ensure the bug occurs""" + assert_equals(cmds.getAttr(a + ".rx"), 0.0) assert_equals(cmds.getAttr(a + ".rx", time=1), 0.0) @@ -40,7 +46,9 @@ def test1(): @with_setup(new) -def test2(): +def test_workaround(): + """Workaround the issue by querying each attribute twice""" + def getAttr(attr, time): cmds.getAttr(attr, time=time - 1) return cmds.getAttr(attr, time=time) From ad7d560ada7429b17d587f22d41b3d55f5ab0120 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Thu, 16 Aug 2018 12:02:28 +0100 Subject: [PATCH 4/4] Add docstrings --- run.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 0d427b5..1d061ff 100644 --- a/run.py +++ b/run.py @@ -31,7 +31,11 @@ def new(): @with_setup(new) def test_bug(): - """Ensure the bug occurs""" + """Test bug + + Ensure that the bug occurs + + """ assert_equals(cmds.getAttr(a + ".rx"), 0.0) assert_equals(cmds.getAttr(a + ".rx", time=1), 0.0) @@ -47,7 +51,35 @@ def test_bug(): @with_setup(new) def test_workaround(): - """Workaround the issue by querying each attribute twice""" + """Test workaround + + Workaround the issue by querying each attribute twice + + """ + + def getAttr(attr, time): + cmds.getAttr(attr, time=time - 1) + return cmds.getAttr(attr, time=time) + + assert_equals(cmds.getAttr(a + ".rx"), 0.0) + assert_equals(cmds.getAttr(a + ".rx", time=1), 0.0) + + # Move handle + cmds.move(0, 15, -10, "|ikHandle1") + + assert_equals(round(cmds.getAttr(a + ".rx"), 0), -14.0) + assert_equals(round(getAttr(a + ".rx", time=1), 0), -14.0) + + +@with_setup(new) +def test_optimisation(): + """Test optimisation + + If the cause of the bug is ikHandle, then once an attribute has + been called twice and triggered the evaluation of ikHandle, the + next dependent node can be called just once. + + """ def getAttr(attr, time): cmds.getAttr(attr, time=time - 1) @@ -69,4 +101,6 @@ def getAttr(attr, time): cmds.move(0, 15, -15, "|ikHandle1") + # Once out-of-date again, the workaround must be applied + assert_not_equals(round(cmds.getAttr(a + ".rx", time=1), 0), -4.0) assert_equals(round(getAttr(a + ".rx", time=1), 0), -4.0)