コード例 #1
0
ファイル: test_quaternion.py プロジェクト: kthulhu/Pyrr
    def test_apply_to_vector_non_unit(self):
        q = Quaternion.from_x_rotation(np.pi)

        # zero length
        v = Vector3([0., 0., 0.])
        self.assertTrue(
            np.allclose(
                q * v,
                quaternion.apply_to_vector(
                    quaternion.create_from_x_rotation(np.pi), [0., 0., 0.])))

        # >1 length
        v = Vector3([2., 0., 0.])
        self.assertTrue(
            np.allclose(
                q * v,
                quaternion.apply_to_vector(
                    quaternion.create_from_x_rotation(np.pi), [2., 0., 0.])))
        v = Vector3([0., 2., 0.])
        self.assertTrue(
            np.allclose(
                q * v,
                quaternion.apply_to_vector(
                    quaternion.create_from_x_rotation(np.pi), [0., 2., 0.])))
        v = Vector3([0., 0., 2.])
        self.assertTrue(
            np.allclose(
                q * v,
                quaternion.apply_to_vector(
                    quaternion.create_from_x_rotation(np.pi), [0., 0., 2.])))
コード例 #2
0
    def test_m44_q_equivalence(self):
        """Test for equivalance of matrix and quaternion rotations.

        Create a matrix and quaternion, rotate each by the same values
        then convert matrix<->quaternion and check the results are the same.
        """
        m = matrix44.create_from_x_rotation(np.pi / 2.)
        mq = quaternion.create_from_matrix(m)

        q = quaternion.create_from_x_rotation(np.pi / 2.)
        qm = matrix44.create_from_quaternion(q)

        self.assertTrue(
            np.allclose(np.dot([1., 0., 0., 1.], m), [1., 0., 0., 1.]))
        self.assertTrue(
            np.allclose(np.dot([1., 0., 0., 1.], qm), [1., 0., 0., 1.]))

        self.assertTrue(
            np.allclose(quaternion.apply_to_vector(q, [1., 0., 0., 1.]),
                        [1., 0., 0., 1.]))
        self.assertTrue(
            np.allclose(quaternion.apply_to_vector(mq, [1., 0., 0., 1.]),
                        [1., 0., 0., 1.]))

        np.testing.assert_almost_equal(q, mq, decimal=5)
        np.testing.assert_almost_equal(m, qm, decimal=5)
コード例 #3
0
    def test_apply_to_vector_non_unit(self):
        q = quaternion.create_from_x_rotation(np.pi)
        # zero length
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 0.]), [0., 0., 0.]))

        # >1 length
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [2., 0., 0.]), [2., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 2., 0.]), [0.,-2., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 2.]), [0., 0.,-2.]))
コード例 #4
0
ファイル: test_quaternion.py プロジェクト: kthulhu/Pyrr
    def test_apply_to_vector_non_unit(self):
        q = quaternion.create_from_x_rotation(np.pi)
        # zero length
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 0.]), [0., 0., 0.]))

        # >1 length
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [2., 0., 0.]), [2., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 2., 0.]), [0.,-2., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 2.]), [0., 0.,-2.]))
コード例 #5
0
 def test_apply_to_vector_z(self):
     quat = quaternion.create_from_z_rotation(np.pi / 2.)
     self.assertTrue(
         np.allclose(quaternion.apply_to_vector(quat, [1., 0., 0.]),
                     [0., -1., 0.]))
     self.assertTrue(
         np.allclose(quaternion.apply_to_vector(quat, [0., 1., 0.]),
                     [1., 0., 0.]))
     self.assertTrue(
         np.allclose(quaternion.apply_to_vector(quat, [0., 0., 1.]),
                     [0., 0., 1.]))
コード例 #6
0
    def rotateAboutOrigin(self, xyz, t, p):
        rp = p - math.pi / 2
        rt = -t

        q1 = quaternion.create_from_z_rotation(rp)
        q2 = quaternion.create_from_x_rotation(rt)
        v = vector3.create(xyz[0], xyz[1], xyz[2])

        v = quaternion.apply_to_vector(q1, v)
        v = quaternion.apply_to_vector(q2, v)

        return v
コード例 #7
0
    def test_apply_to_vector_non_unit(self):
        q = Quaternion.from_x_rotation(np.pi)

        # zero length
        v = Vector3([0., 0., 0.])
        self.assertTrue(np.allclose(q * v, quaternion.apply_to_vector(quaternion.create_from_x_rotation(np.pi), [0., 0., 0.])))

        # >1 length
        v = Vector3([2., 0., 0.])
        self.assertTrue(np.allclose(q * v, quaternion.apply_to_vector(quaternion.create_from_x_rotation(np.pi), [2., 0., 0.])))
        v = Vector3([0., 2., 0.])
        self.assertTrue(np.allclose(q * v, quaternion.apply_to_vector(quaternion.create_from_x_rotation(np.pi), [0., 2., 0.])))
        v = Vector3([0., 0., 2.])
        self.assertTrue(np.allclose(q * v, quaternion.apply_to_vector(quaternion.create_from_x_rotation(np.pi), [0., 0., 2.])))
コード例 #8
0
ファイル: camera.py プロジェクト: jsa4000/OpenGL-Python
 def roll(self, value):
     """Rotate using the forward direction
     """
     rotation = Quaternion.from_axis_rotation(self._forward,
                                              value * self._speed)
     self._up = normalize(quaternion.apply_to_vector(rotation, self._up))
     return self
コード例 #9
0
ファイル: camera.py プロジェクト: jsa4000/OpenGL-Python
 def yaw(self, value):
     """Rotate using up direction
     """
     rotation = Quaternion.from_axis_rotation(self._up, value * self._speed)
     self._forward = normalize(
         quaternion.apply_to_vector(rotation, self._forward))
     return self
コード例 #10
0
ファイル: octasphere.py プロジェクト: hpparvi/PyTransit
def octasphere(ndivisions: int):
    """Creates a unit sphere using octagon subdivision.

    Creates a unit sphere using octagon subdivision. Modified slightly from the original code
    by Philip Rideout (https://prideout.net/blog/octasphere).
    """

    n = 2**ndivisions + 1
    num_verts = n * (n + 1) // 2
    verts = empty((num_verts, 3))
    j = 0
    for i in range(n):
        theta = pi * 0.5 * i / (n - 1)
        point_a = [0, sin(theta), cos(theta)]
        point_b = [cos(theta), sin(theta), 0]
        num_segments = n - 1 - i
        j = compute_geodesic(verts, j, point_a, point_b, num_segments)
    assert len(verts) == num_verts

    num_faces = (n - 2) * (n - 1) + n - 1
    faces = empty((num_faces, 3), dtype='int')
    f, j0 = 0, 0
    for col_index in range(n - 1):
        col_height = n - 1 - col_index
        j1 = j0 + 1
        j2 = j0 + col_height + 1
        j3 = j0 + col_height + 2
        for row in range(col_height - 1):
            faces[f + 0] = [j0 + row, j1 + row, j2 + row]
            faces[f + 1] = [j2 + row, j1 + row, j3 + row]
            f = f + 2
        row = col_height - 1
        faces[f] = [j0 + row, j1 + row, j2 + row]
        f = f + 1
        j0 = j2

    euler_angles = array([
        [0, 0, 0],
        [0, 1, 0],
        [0, 2, 0],
        [0, 3, 0],
        [1, 0, 0],
        [1, 0, 1],
        [1, 0, 2],
        [1, 0, 3],
    ]) * pi * 0.5
    quats = (quaternion.create_from_eulers(e) for e in euler_angles)

    offset, combined_verts, combined_faces = 0, [], []
    for quat in quats:
        rotated_verts = [quaternion.apply_to_vector(quat, v) for v in verts]
        rotated_faces = faces + offset
        combined_verts.append(rotated_verts)
        combined_faces.append(rotated_faces)
        offset = offset + len(verts)

    return vstack(combined_verts), vstack(combined_faces)
コード例 #11
0
ファイル: camera.py プロジェクト: jsa4000/OpenGL-Python
 def pitch(self, value):
     """ Rotate using cross product between up and forward vectors (side).
     """
     side = normalize(np.cross(self._up, self._forward))
     rotation = Quaternion.from_axis_rotation(side, value * self._speed)
     self._forward = normalize(
         quaternion.apply_to_vector(rotation, self._forward))
     self._up = normalize(np.cross(self._forward, side))
     return self
コード例 #12
0
ファイル: test_matrix_quaternion.py プロジェクト: abarch/Pyrr
    def test_m44_q_equivalence(self):
        """Test for equivalance of matrix and quaternion rotations.

        Create a matrix and quaternion, rotate each by the same values
        then convert matrix<->quaternion and check the results are the same.
        """
        m = matrix44.create_from_x_rotation(np.pi / 2.)
        mq = quaternion.create_from_matrix(m)

        q = quaternion.create_from_x_rotation(np.pi / 2.)
        qm = matrix44.create_from_quaternion(q)

        self.assertTrue(np.allclose(np.dot([1.,0.,0.,1.], m), [1.,0.,0.,1.]))
        self.assertTrue(np.allclose(np.dot([1.,0.,0.,1.], qm), [1.,0.,0.,1.]))

        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1.,0.,0.,1.]), [1.,0.,0.,1.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(mq, [1.,0.,0.,1.]), [1.,0.,0.,1.]))

        np.testing.assert_almost_equal(q, mq, decimal=5)
        np.testing.assert_almost_equal(m, qm, decimal=5)
コード例 #13
0
ファイル: test_quaternion.py プロジェクト: kthulhu/Pyrr
    def test_apply_to_vector_z(self):
        # 180 degree turn around Z axis
        q = quaternion.create_from_z_rotation(np.pi)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [-1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [0.,-1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))

        # 90 degree rotation around Z axis
        q = quaternion.create_from_z_rotation(np.pi / 2.)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [0., 1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [-1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))

        # -90 degree rotation around Z axis
        q = quaternion.create_from_z_rotation(-np.pi / 2.)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [0.,-1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))
コード例 #14
0
    def test_apply_to_vector_z(self):
        # 180 degree turn around Z axis
        q = quaternion.create_from_z_rotation(np.pi)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [-1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [0.,-1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))

        # 90 degree rotation around Z axis
        q = quaternion.create_from_z_rotation(np.pi / 2.)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [0., 1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [-1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))

        # -90 degree rotation around Z axis
        q = quaternion.create_from_z_rotation(-np.pi / 2.)
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [1., 0., 0.]), [0.,-1., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 1., 0.]), [1., 0., 0.]))
        self.assertTrue(np.allclose(quaternion.apply_to_vector(q, [0., 0., 1.]), [0., 0., 1.]))
コード例 #15
0
    def test_operators_vector4(self):
        q = Quaternion.from_x_rotation(0.5)
        v = Vector4([1.,0.,0.,1.])

        # add
        self.assertRaises(ValueError, lambda: q + v)

        # subtract
        self.assertRaises(ValueError, lambda: q - v)

        # multiply
        self.assertTrue(np.array_equal(q * v, quaternion.apply_to_vector(quaternion.create_from_x_rotation(0.5), [1.,0.,0.,1.])))

        # divide
        self.assertRaises(ValueError, lambda: q / v)
コード例 #16
0
ファイル: camera.py プロジェクト: jsa4000/OpenGL-Python
 def orient(self, x, y):
     """ Orient the current camera with the current x, y 
         The function will use two quaternions for computing the final rotation. By using 
         the current up and side vectors of the camera. The angle used for the rotations 
         are x and y passed by parameters. The function will normalize the new axis vectors
         for the camera by the current rotation. 
         Remark: there is no translation like in Orbit functionality.
     """
     side = normalize(np.cross(self._up, self._forward))
     rotationYaw = Quaternion.from_axis_rotation(
         self._up, -x * self._speed * self._sensitivity)
     rotationPitch = Quaternion.from_axis_rotation(
         side, y * self._speed * self._sensitivity)
     rotation = rotationYaw * rotationPitch
     self._forward = normalize(
         quaternion.apply_to_vector(rotation, self._forward))
     return self
コード例 #17
0
ファイル: octasphere.py プロジェクト: hpparvi/PyTransit
def compute_geodesic(dst, index, point_a, point_b, num_segments):
    """Given two points on a unit sphere, returns a sequence of surface
    points that lie between them along a geodesic curve."""

    angle_between_endpoints = acos(dot(point_a, point_b))
    rotation_axis = cross(point_a, point_b)
    dst[index] = point_a
    index = index + 1
    if num_segments == 0:
        return index
    dtheta = angle_between_endpoints / num_segments
    for point_index in range(1, num_segments):
        theta = point_index * dtheta
        q = quaternion.create_from_axis_rotation(rotation_axis, theta)
        dst[index] = quaternion.apply_to_vector(q, point_a)
        index = index + 1
    dst[index] = point_b
    return index + 1
コード例 #18
0
 def test_apply_to_vector_unit_x(self):
     result = quaternion.apply_to_vector([0., 0., 0., 1.], [1., 0., 0.])
     np.testing.assert_almost_equal(result, [1., 0., 0.], decimal=5)
コード例 #19
0
    def load(self, md5anim, frame):
        # we don't need to upload the parents values
        # so just leave as 'int'
        # the parent can be negative (root is -1), so it must be signed
        self.parents = numpy.empty(md5anim.hierarchy.num_joints, dtype='int')
        self.positions = numpy.empty((md5anim.hierarchy.num_joints, 3),
                                     dtype='float32')
        self.orientations = numpy.empty((md5anim.hierarchy.num_joints, 4),
                                        dtype='float32')

        for index, (hierarchy_joint, base_frame_joint) in enumerate(
                zip(md5anim.hierarchy, md5anim.base_frame)):
            # set the parent now as we can't set it in the named tuple
            self.parents[index] = hierarchy_joint.parent

            # get the current joint
            joint = self.joint(index)

            # begin with the original base frame values
            joint.position[:] = base_frame_joint.position
            joint.orientation[:] = base_frame_joint.orientation

            # overlay with values from our frame
            # we know which values to get from the joint's start_index
            # and the joint's flag
            frame_index = hierarchy_joint.start_index
            if hierarchy_joint.flags & 1:
                joint.position[0] = frame.value(frame_index)
                frame_index += 1
            if hierarchy_joint.flags & 2:
                joint.position[1] = frame.value(frame_index)
                frame_index += 1
            if hierarchy_joint.flags & 4:
                joint.position[2] = frame.value(frame_index)
                frame_index += 1
            if hierarchy_joint.flags & 8:
                joint.orientation[0] = frame.value(frame_index)
                frame_index += 1
            if hierarchy_joint.flags & 16:
                joint.orientation[1] = frame.value(frame_index)
                frame_index += 1
            if hierarchy_joint.flags & 32:
                joint.orientation[2] = frame.value(frame_index)
                frame_index += 1

            # compute the W component of the quaternion
            joint.orientation[3] = compute_quaternion_w(
                joint.orientation[0], joint.orientation[1],
                joint.orientation[2])

            # parents should always be an bone we've
            # previously calculated
            assert joint.parent < index

            # check if the joint has a parent
            if joint.parent >= 0:
                # get the parent joint
                parent = self.joint(joint.parent)

                # make this joint relative to the parent
                # rotate our position by our parents
                rotated_position = quaternion.apply_to_vector(
                    parent.orientation, joint.position)

                # add our parent's position
                joint.position[:] = parent.position + rotated_position

                # multiply our orientation by our parent's
                rotated_orientation = quaternion.cross(parent.orientation,
                                                       joint.orientation)

                # normalise our orientation
                joint.orientation[:] = quaternion.normalise(
                    rotated_orientation)
コード例 #20
0
ファイル: test_quaternion.py プロジェクト: abarch/Pyrr
 def test_apply_to_vector_z(self):
     quat = quaternion.create_from_z_rotation(np.pi / 2.)
     self.assertTrue(np.allclose(quaternion.apply_to_vector(quat,[1.,0.,0.]), [0.,-1.,0.]))
     self.assertTrue(np.allclose(quaternion.apply_to_vector(quat,[0.,1.,0.]), [1.,0.,0.]))
     self.assertTrue(np.allclose(quaternion.apply_to_vector(quat,[0.,0.,1.]), [0.,0.,1.]))
コード例 #21
0
 def test_apply_to_vector_unit_x(self):
     result = quaternion.apply_to_vector([0., 0., 0., 1.], [1., 0., 0.])
     np.testing.assert_almost_equal(result, [1., 0., 0.], decimal=5)
コード例 #22
0
ファイル: main.py プロジェクト: sn-hda/skeleton_tracker
def compute_angles(transforms, rotations):
    angles = []

    #########################################
    ### Elbows - simple angle calculation ###
    #########################################
    elbow_angles = []
    for i in range(2):  # Iterate over joint chains - get right and left

        # Create vectors from transforms
        vector_shoulder_elbow = np.array(
            [transforms[i][2][0], transforms[i][2][1], transforms[i][2][2]])
        vector_elbow_wrist = np.array(
            [transforms[i][3][0], transforms[i][3][1], transforms[i][3][2]])

        # Rotate vector_elbow_wrist to match vector_shoulder_elbow coordinate system
        inverse_quaternion = quaternion.inverse(rotations[i][2])
        vector_elbow_wrist = quaternion.apply_to_vector(
            inverse_quaternion, vector_elbow_wrist)

        # Angle between 2 vectors
        angle = np.arccos(
            np.dot(vector_shoulder_elbow, vector_elbow_wrist) /
            (np.linalg.norm(vector_shoulder_elbow) *
             np.linalg.norm(vector_elbow_wrist)))

        # Limit angle
        if angle > 3 * math.pi / 4:
            angle = 3 * math.pi / 4
        elif angle < 0:
            angle = 0

        elbow_angles.append(angle)

    ###########################################################################################
    ### Shoulders, 2 angles per shoulder - projecting upper arm on two perpendicular planes ###
    ###########################################################################################
    shoulder_angles = []
    for i in range(2):  # Iterate over joint chains - get right and left

        # Create vectors from transformations
        vector_hip_neck = np.array(
            [transforms[i][0][0], transforms[i][0][1], transforms[i][0][2]])
        vector_neck_shoulder = np.array(
            [transforms[i][1][0], transforms[i][1][1], transforms[i][1][2]])
        vector_shoulder_elbow = np.array(
            [transforms[i][2][0], transforms[i][2][1], transforms[i][2][2]])

        # Rotate vector_shoulder_elbow to match vector_neck_shoulder coordinate system
        inverse_quaternion = quaternion.inverse(rotations[i][1])
        vector_shoulder_elbow = quaternion.apply_to_vector(
            inverse_quaternion, vector_shoulder_elbow)

        # Rotate vector_hip_neck to match vector_neck_shoulder coordinate system
        vector_hip_neck = quaternion.apply_to_vector(rotations[i][0],
                                                     vector_hip_neck)

        # Calculate normal vector for plane set by vector_hip_neck and vector_neck_shoulder
        vector_normal_forward = np.cross(vector_hip_neck, vector_neck_shoulder)

        # Initialize second normal vector
        vector_normal_side = vector_neck_shoulder

        # Project vector_shoulder_elbow to plane set by vector_normal_forward
        vector_shoulder_elbow_parallel = vector_shoulder_elbow - (
            (np.dot(vector_shoulder_elbow, vector_normal_forward) /
             math.pow(np.linalg.norm(vector_normal_forward), 2)) *
            vector_normal_forward)

        # Project vector_shoulder_elbow to plane set by vector_normal_side
        vector_shoulder_elbow_perpendicular = vector_shoulder_elbow - (
            (np.dot(vector_shoulder_elbow, vector_normal_side) / math.pow(
                np.linalg.norm(vector_normal_side), 2)) * vector_normal_side)
        if i == 1:
            vector_shoulder_elbow_perpendicular = -vector_shoulder_elbow_perpendicular

        # Angles between 2 vectors
        angle_parallel = np.arccos(
            np.dot(vector_normal_side, vector_shoulder_elbow_parallel) /
            (np.linalg.norm(vector_normal_side) *
             np.linalg.norm(vector_shoulder_elbow_parallel)))
        angle_perpendicular = np.arccos(
            np.dot(vector_normal_forward, vector_shoulder_elbow_perpendicular)
            / (np.linalg.norm(vector_normal_forward) *
               np.linalg.norm(vector_shoulder_elbow_perpendicular)))

        # Fix ambiquity of results below and above zero-level
        if vector_shoulder_elbow[1] > 0:
            angle_parallel += math.pi / 2
            angle_perpendicular = math.fabs(angle_perpendicular +
                                            (math.pi / 2))
        # Set angles to match the simulation
        else:
            angle_parallel = math.fabs(angle_parallel - (math.pi / 2))
            angle_perpendicular = math.fabs(angle_perpendicular -
                                            (math.pi / 2))

        # In simulation, right goes down from zero while left goes up from zero
        if i == 0:
            angle_parallel = -angle_parallel

        # Set angle_parallel to zero if hand is above parallel
        if vector_shoulder_elbow[1] > 0:
            if vector_shoulder_elbow[0] > 0 and i == 0:
                angle_parallel = 0
            elif vector_shoulder_elbow[0] < 0 and i == 1:
                angle_parallel = 0

        # Limit parallel angle
        if angle_parallel > 0.75:
            angle_parallel = 0.75
        elif angle_parallel < -0.75:
            angle_parallel = -0.75

        # Set perpendicular angle to zero if it's unexpectedly high or low - usually if elbows are farther from Kinect than shoulders
        if angle_perpendicular > math.pi + math.pi / 4:
            angle_perpendicular = 0
        elif angle_perpendicular < -math.pi / 4:
            angle_perpendicular = 0
        # Limit perpendicular angle
        elif angle_perpendicular > math.pi:
            angle_perpendicular = math.pi
        elif angle_perpendicular < 0:
            angle_perpendicular = 0

        shoulder_angles.append(angle_parallel)
        shoulder_angles.append(angle_perpendicular)

    ######################
    ### Bicep rotation ###
    ######################
    bicep_angles = []
    for i in range(2):  # Iterate over joint chains - get right and left

        # Create vectors from transformations
        vector_shoulder_elbow = np.array(
            [transforms[i][2][0], transforms[i][2][1], transforms[i][2][2]])

        vector_elbow_hand = np.array(
            [transforms[i][3][0], transforms[i][3][1], transforms[i][3][2]])

        # Rotate vector_shoulder_elbow to match vector_neck_shoulder coordinate system
        inverse_quaternion = quaternion.inverse(rotations[i][1])
        vector_shoulder_elbow = quaternion.apply_to_vector(
            inverse_quaternion, vector_shoulder_elbow)

        # Calculate a unit vector from vector_elbow_hand
        vector_elbow_hand_lenght = np.linalg.norm(vector_elbow_hand)
        vector_elbow_hand_unit = vector_elbow_hand / vector_elbow_hand_lenght

        # Calculate bicep rotation angle
        angle = 2 * math.sin(vector_elbow_hand_unit[1])

        if vector_shoulder_elbow[1] > 0 and i == 1:
            angle = angle - math.pi
        elif vector_shoulder_elbow[1] > 0 and i == 0:
            angle = -angle + math.pi
        elif vector_shoulder_elbow[1] < 0 and i == 0:
            angle = -angle

        bicep_angles.append(angle)

    #################
    ### Head tilt ###
    #################
    head_angles = []
    # Create vectors from transformations
    vector_neck_head = np.array(
        [transforms[0][5][0], transforms[0][5][1], transforms[0][5][2]])

    # Calculate a unit vector from vector_neck_head
    vector_neck_head_lenght = np.linalg.norm(vector_neck_head)
    vector_neck_head_unit = vector_neck_head / vector_neck_head_lenght

    # Calculate head rotation angle
    angle = math.sin(vector_neck_head_unit[0])

    # Limit angle
    if angle > 0.3:
        angle = 0.3
    elif angle < -0.3:
        angle = -0.3

    head_angles.append(angle)

    ##################
    ### Waist lean ###
    ##################s
    waist_angles = []
    # Create vector up from shoulder line
    vector_normal_up = np.cross(vector_normal_side, vector_normal_forward)

    # Calculate a unit vector from vector_normal_up
    vector_normal_up_lenght = np.linalg.norm(vector_normal_up)
    vector_normal_up_unit = vector_normal_up / vector_normal_up_lenght

    # Calculate waist lean angle
    angle = math.sin(vector_neck_head_unit[0])

    # Limit angle
    if angle > 0.3:
        angle = 0.3
    elif angle < -0.3:
        angle = -0.3

    waist_angles.append(angle)

    # Test print
    outputStr = '{}\n'.format(vector_normal_up)
    rospy.loginfo(outputStr)

    angles.append(elbow_angles)
    angles.append(shoulder_angles)
    angles.append(bicep_angles)
    angles.append(head_angles)
    angles.append(waist_angles)

    return angles