# [Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [4334] trunk/py/scripts/addons/rigify/ rig_ui_template.py: Rigify: fixed two bugs in IK/ FK snapping that made it fail in some cases.

Nathan Vegdahl cessen at cessen.com
Thu Feb 28 22:27:10 CET 2013

```Revision: 4334
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=4334
Author:   cessen
Date:     2013-02-28 21:27:10 +0000 (Thu, 28 Feb 2013)
Log Message:
-----------
Rigify: fixed two bugs in IK/FK snapping that made it fail in some cases.

Modified Paths:
--------------

===================================================================
--- trunk/py/scripts/addons/rigify/rig_ui_template.py	2013-02-27 16:24:27 UTC (rev 4333)
+++ trunk/py/scripts/addons/rigify/rig_ui_template.py	2013-02-28 21:27:10 UTC (rev 4334)
@@ -21,11 +21,45 @@
UI_SLIDERS = '''
import bpy
from mathutils import Matrix, Vector
-from math import acos
+from math import acos, pi

rig_id = "%s"

+############################
+## Math utility functions ##
+############################
+
+def perpendicular_vector(v):
+    """ Returns a vector that is perpendicular to the one given.
+        The returned vector is _not_ guaranteed to be normalized.
+    """
+    # Create a vector that is not aligned with v.
+    # It doesn't matter what vector.  Just any vector
+    # that's guaranteed to not be pointing in the same
+    # direction.
+    if abs(v[0]) < abs(v[1]):
+        tv = Vector((1,0,0))
+    else:
+        tv = Vector((0,1,0))
+
+    # Use cross prouct to generate a vector perpendicular to
+    # both tv and (more importantly) v.
+    return v.cross(tv)
+
+
+def rotation_difference(mat1, mat2):
+    """ Returns the shortest-path rotational difference between two
+        matrices.
+    """
+    q1 = mat1.to_quaternion()
+    q2 = mat2.to_quaternion()
+    angle = acos(min(1,max(-1,q1.dot(q2)))) * 2
+    if angle > pi:
+        angle = -angle + (2*pi)
+    return angle
+
+
#########################################
## "Visual Transform" helper functions ##
#########################################
@@ -162,20 +196,8 @@
# tip of ik_last
ikv = b - a

-    # Create a vector that is not aligned with ikv.
-    # It doesn't matter what vector.  Just any vector
-    # that's guaranteed to not be pointing in the same
-    # direction.  In this case, we create a unit vector
-    # on the axis of the smallest component of ikv.
-    if abs(ikv[0]) < abs(ikv[1]) and abs(ikv[0]) < abs(ikv[2]):
-        v = Vector((1,0,0))
-    elif abs(ikv[1]) < abs(ikv[2]):
-        v = Vector((0,1,0))
-    else:
-        v = Vector((0,0,1))
-
# Get a vector perpendicular to ikv
-    pv = v.cross(ikv).normalized() * length
+    pv = perpendicular_vector(ikv).normalized() * length

def set_pole(pvi):
""" Set pole target's position based on a vector
@@ -194,26 +216,22 @@
set_pole(pv)

# Get the rotation difference between ik_first and match_bone
-    q1 = ik_first.matrix.to_quaternion()
-    q2 = match_bone.matrix.to_quaternion()
-    angle = acos(min(1,max(-1,q1.dot(q2)))) * 2
+    angle = rotation_difference(ik_first.matrix, match_bone.matrix)

-    # Compensate for the rotation difference
-    if angle > 0.0001:
-        pv = Matrix.Rotation(angle, 4, ikv).to_quaternion() * pv
-        set_pole(pv)
+    # Try compensating for the rotation difference in both directions
+    pv1 = Matrix.Rotation(angle, 4, ikv) * pv
+    set_pole(pv1)
+    ang1 = rotation_difference(ik_first.matrix, match_bone.matrix)

-        # Get rotation difference again, to see if we
-        # compensated in the right direction
-        q1 = ik_first.matrix.to_quaternion()
-        q2 = match_bone.matrix.to_quaternion()
-        angle2 = acos(min(1,max(-1,q1.dot(q2)))) * 2
-        if angle2 > 0.0001:
-            # Compensate in the other direction
-            pv = Matrix.Rotation((angle*(-2)), 4, ikv).to_quaternion() * pv
-            set_pole(pv)
+    pv2 = Matrix.Rotation(-angle, 4, ikv) * pv
+    set_pole(pv2)
+    ang2 = rotation_difference(ik_first.matrix, match_bone.matrix)

+    # Do the one with the smaller angle
+    if ang1 < ang2:
+        set_pole(pv1)

+
def fk2ik_arm(obj, fk, ik):
""" Matches the fk bones in an arm rig to the ik bones.
obj: armature object

```