From 8166fec0e04267dc2106eb198c9624cd0bf02c6d Mon Sep 17 00:00:00 2001 From: Chris Howe <1P-Cusack@1stplayable.com> Date: Tue, 6 Jun 2017 12:11:57 -0400 Subject: [PATCH] Minor changes based on code review feedback See https://worklist.net/21317, https://github.com/highfidelity/hifi/pull/10609 and https://github.com/highfidelity/hifi/pull/10609#pullrequestreview-42090197 --- interface/src/avatar/MyAvatar.cpp | 148 +++++++++++------------------- interface/src/avatar/MyAvatar.h | 18 ++-- scripts/avatarToWorldTests.js | 64 ++++++------- scripts/worldToAvatarTests.js | 58 ++++++------ 4 files changed, 124 insertions(+), 164 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a24a737301..7a9864a737 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -773,114 +773,78 @@ controller::Pose MyAvatar::getRightHandTipPose() const { return pose; } +glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const { + glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified + glm::quat jointRot = getRotation();//default value if no or invalid joint specified + if (jointIndex != -1) { + if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { + _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); + } + else { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + } + glm::vec3 modelOffset = position - jointPos; + glm::vec3 jointSpacePosition = glm::inverse(jointRot) * modelOffset; -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -//:1P: conversion functions for world-space to avatar-space or vice versa -glm::vec3 MyAvatar::worldToAvatarPoint(const glm::vec3& position, const int jointIndex) const -{ - glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified - glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - glm::vec3 modelOffset = position - jointPos; - glm::vec3 modelPosition = glm::inverse(jointRot) * modelOffset; - - return modelPosition; + return jointSpacePosition; } -glm::vec3 MyAvatar::worldToAvatarDirection(const glm::vec3& worldDir, const int jointIndex) const -{ - glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } +glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const { + glm::quat jointRot = getRotation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } - glm::vec3 avatarDir = glm::inverse(jointRot) * worldDir; - return avatarDir; + glm::vec3 jointSpaceDir = glm::inverse(jointRot) * worldDir; + return jointSpaceDir; } -glm::quat MyAvatar::worldToAvatarRotation(const glm::quat& worldRot, const int jointIndex) const -{ - glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - glm::quat avatarRot = glm::inverse(jointRot) * worldRot; - return avatarRot; +glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const { + glm::quat jointRot = getRotation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::quat jointSpaceRot = glm::inverse(jointRot) * worldRot; + return jointSpaceRot; } -glm::vec3 MyAvatar::avatarToWorldPoint(const glm::vec3& avatarPos, const int jointIndex) const -{ - glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified - glm::quat jointRot = getRotation();//default value if no or invalid joint specified +glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const { + glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified + glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } + if (jointIndex != -1) { + if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { + _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); + } + else { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + } - glm::vec3 worldOffset = jointRot * avatarPos; - glm::vec3 worldPos = jointPos + worldOffset; + glm::vec3 worldOffset = jointRot * jointSpacePos; + glm::vec3 worldPos = jointPos + worldOffset; - return worldPos; + return worldPos; } -glm::vec3 MyAvatar::avatarToWorldDirection(const glm::vec3& avatarDir, const int jointIndex) const -{ - glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - glm::vec3 worldDir = jointRot * avatarDir; - return worldDir; +glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const { + glm::quat jointRot = getRotation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::vec3 worldDir = jointRot * jointSpaceDir; + return worldDir; } -glm::quat MyAvatar::avatarToWorldRotation(const glm::quat& avatarRot, const int jointIndex) const -{ - glm::quat jointRot = getRotation();//default value if no or invalid joint specified - if (jointIndex != -1) - { - if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot)) - { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - glm::quat worldRot = jointRot * avatarRot; - return worldRot; +glm::quat MyAvatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const { + glm::quat jointRot = getRotation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::quat worldRot = jointRot * jointSpaceRot; + return worldRot; } -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - - // virtual void MyAvatar::render(RenderArgs* renderArgs) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a4c9f19316..b3e5f277b9 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -379,18 +379,14 @@ public: Q_INVOKABLE controller::Pose getLeftHandTipPose() const; Q_INVOKABLE controller::Pose getRightHandTipPose() const; - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - //:1P: world-space to avatar-space rigconversion functions - Q_INVOKABLE glm::vec3 worldToAvatarPoint(const glm::vec3& position, const int jointIndex = -1) const; - Q_INVOKABLE glm::vec3 worldToAvatarDirection(const glm::vec3& direction, const int jointIndex = -1) const; - Q_INVOKABLE glm::quat worldToAvatarRotation(const glm::quat& rotation, const int jointIndex = -1) const; + // world-space to avatar-space rigconversion functions + Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const; + Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const; - Q_INVOKABLE glm::vec3 avatarToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const; - Q_INVOKABLE glm::vec3 avatarToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const; - Q_INVOKABLE glm::quat avatarToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// + Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const; + Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; } void updateLookAtTargetAvatar(); diff --git a/scripts/avatarToWorldTests.js b/scripts/avatarToWorldTests.js index 35e9cc59eb..c6e23fc81b 100644 --- a/scripts/avatarToWorldTests.js +++ b/scripts/avatarToWorldTests.js @@ -20,45 +20,45 @@ var debugBoxBaseProperties = { userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }" }; -//avatarToWorldPoint +//jointToWorldPoint // create sphere for finger on left hand // each frame, calculate world position of finger, with some offset // update sphere to match this position -var avatarToWorldPointTest_sphereEntity; -function avatarToWorldPointTest() { +var jointToWorldPointTest_sphereEntity; +function jointToWorldPointTest() { var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4"); var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 }; - var worldPos = MyAvatar.avatarToWorldPoint(jointOffset_WorldSpace, jointIndex); + var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex); var jointSphereProps = Object.create(debugSphereBaseProperties); - jointSphereProps.name = "avatarToWorldPointTest_Sphere"; + jointSphereProps.name = "jointToWorldPointTest_Sphere"; jointSphereProps.color = { blue: 240, green: 150, red: 150 }; jointSphereProps.position = worldPos; - avatarToWorldPointTest_sphereEntity = Entities.addEntity(jointSphereProps); + jointToWorldPointTest_sphereEntity = Entities.addEntity(jointSphereProps); } -function avatarToWorldPointTest_update(deltaTime) { +function jointToWorldPointTest_update(deltaTime) { var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4"); var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 }; - var worldPos = MyAvatar.avatarToWorldPoint(jointOffset_WorldSpace, jointIndex); + var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex); var newProperties = { position: worldPos }; - Entities.editEntity(avatarToWorldPointTest_sphereEntity, newProperties); + Entities.editEntity(jointToWorldPointTest_sphereEntity, newProperties); } -//avatarToWorldDirection +//jointToWorldDirection // create line in world space // each frame calculate world space direction of players head z axis // update line to match -var avatarToWorldDirectionTest_lineEntity; -function avatarToWorldDirectionTest() { +var jointToWorldDirectionTest_lineEntity; +function jointToWorldDirectionTest() { var jointIndex = MyAvatar.getJointIndex("Head"); var avatarPos = MyAvatar.getJointPosition(jointIndex); var jointDir = { x: 1, y: 0, z: 1 }; - var worldDir = MyAvatar.avatarToWorldDirection(jointDir, jointIndex); + var worldDir = MyAvatar.jointToWorldDirection(jointDir, jointIndex); print(worldDir.x); print(worldDir.y); print(worldDir.z); - avatarToWorldDirectionTest_lineEntity = Entities.addEntity({ + jointToWorldDirectionTest_lineEntity = Entities.addEntity({ type: "Line", color: {red: 250, green: 0, blue: 0}, dimensions: {x: 5, y: 5, z: 5}, @@ -72,11 +72,11 @@ function avatarToWorldDirectionTest() { position : avatarPos, }); } -function avatarToWorldDirection_update(deltaTime) { +function jointToWorldDirection_update(deltaTime) { var jointIndex = MyAvatar.getJointIndex("Head"); var avatarPos = MyAvatar.getJointPosition(jointIndex); var jointDir = { x: 1, y: 0, z: 0 }; - var worldDir = MyAvatar.avatarToWorldDirection(jointDir, jointIndex); + var worldDir = MyAvatar.jointToWorldDirection(jointDir, jointIndex); var newProperties = { linePoints: [{ x: 0, @@ -87,41 +87,41 @@ function avatarToWorldDirection_update(deltaTime) { position : avatarPos }; - Entities.editEntity(avatarToWorldDirectionTest_lineEntity, newProperties); + Entities.editEntity(jointToWorldDirectionTest_lineEntity, newProperties); } -//avatarToWorldRotation +//jointToWorldRotation // create box in world space // each frame calculate world space rotation of players head // update box rotation to match -var avatarToWorldRotationTest_boxEntity; -function avatarToWorldRotationTest() { +var jointToWorldRotationTest_boxEntity; +function jointToWorldRotationTest() { var jointIndex = MyAvatar.getJointIndex("Head"); var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex); var jointRot = MyAvatar.getJointRotation(jointIndex); - var jointRot_WorldSpace = MyAvatar.avatarToWorldRotation(jointRot, jointIndex); + var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex); var boxProps = Object.create(debugBoxBaseProperties); - boxProps.name = "avatarToWorldRotationTest_Box"; + boxProps.name = "jointToWorldRotationTest_Box"; boxProps.color = { blue: 250, green: 250, red: 250 }; boxProps.position = jointPosition_WorldSpace; boxProps.rotation = jointRot_WorldSpace; - avatarToWorldRotationTest_boxEntity = Entities.addEntity(boxProps); + jointToWorldRotationTest_boxEntity = Entities.addEntity(boxProps); } -function avatarToWorldRotationTest_update(deltaTime) { +function jointToWorldRotationTest_update(deltaTime) { var jointIndex = MyAvatar.getJointIndex("Head"); var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex); var jointRot = MyAvatar.getJointRotation(jointIndex); - var jointRot_WorldSpace = MyAvatar.avatarToWorldRotation(jointRot, jointIndex); + var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex); var newProperties = { position: jointPosition_WorldSpace, rotation: jointRot_WorldSpace }; - Entities.editEntity(avatarToWorldRotationTest_boxEntity, newProperties); + Entities.editEntity(jointToWorldRotationTest_boxEntity, newProperties); } -avatarToWorldPointTest(); -Script.update.connect(avatarToWorldPointTest_update); +jointToWorldPointTest(); +Script.update.connect(jointToWorldPointTest_update); -avatarToWorldDirectionTest(); -Script.update.connect(avatarToWorldDirection_update); +jointToWorldDirectionTest(); +Script.update.connect(jointToWorldDirection_update); -avatarToWorldRotationTest(); -Script.update.connect(avatarToWorldRotationTest_update); +jointToWorldRotationTest(); +Script.update.connect(jointToWorldRotationTest_update); diff --git a/scripts/worldToAvatarTests.js b/scripts/worldToAvatarTests.js index d860517a22..6f0b19dc2d 100644 --- a/scripts/worldToAvatarTests.js +++ b/scripts/worldToAvatarTests.js @@ -20,22 +20,22 @@ var debugBoxBaseProperties = { userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }" }; -//worldToAvatarPoint +//worldToJointPoint // calculate position offset from joint using getJointPosition -// pass through worldToAvatarPoint to get offset in joint space of players joint +// pass through worldToJointPoint to get offset in joint space of players joint // create a blue sphere and attach it to players joint using the joint space offset // The two spheres should appear in the same place, but the blue sphere will follow the avatar -function worldToAvatarPointTest() { +function worldToJointPointTest() { var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4"); var avatarPos = MyAvatar.position; var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex); var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 }; var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace); - var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex); + var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex); var jointSphereProps = Object.create(debugSphereBaseProperties); - jointSphereProps.name = "worldToAvatarPointTest_Joint"; + jointSphereProps.name = "worldToJointPointTest_Joint"; jointSphereProps.color = { blue: 240, green: 150, red: 150 }; jointSphereProps.localPosition = jointPosition_JointSpaceOffset; jointSphereProps.parentID = AVATAR_SELF_ID; @@ -43,29 +43,29 @@ function worldToAvatarPointTest() { Entities.addEntity(jointSphereProps); var worldSphereProps = Object.create(debugSphereBaseProperties); - worldSphereProps.name = "worldToAvatarPointTest_World"; + worldSphereProps.name = "worldToJointPointTest_World"; worldSphereProps.color = { blue: 150, green: 250, red: 150 }; worldSphereProps.position = jointPosition_WorldSpaceOffset; Entities.addEntity(worldSphereProps); } -//worldToAvatarDirection +//worldToJointDirection // create line and attach to avatars head // each frame calculate direction of world x axis in joint space of players head // update arrow orientation to match -var worldToAvatarDirectionTest_lineEntity; -function worldToAvatarDirectionTest() { +var worldToJointDirectionTest_lineEntity; +function worldToJointDirectionTest() { var jointIndex = MyAvatar.getJointIndex("Head"); var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex); var jointOffset_WorldSpace = { x: 0, y: 0, z: 0 }; var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace); - var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex); + var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex); var worldDir = { x: 1, y: 0, z: 0 }; - var avatarDir = MyAvatar.worldToAvatarDirection(worldDir, jointIndex); + var avatarDir = MyAvatar.worldToJointDirection(worldDir, jointIndex); - worldToAvatarDirectionTest_lineEntity = Entities.addEntity({ + worldToJointDirectionTest_lineEntity = Entities.addEntity({ type: "Line", color: {red: 200, green: 250, blue: 0}, dimensions: {x: 5, y: 5, z: 5}, @@ -82,10 +82,10 @@ function worldToAvatarDirectionTest() { }); } -function worldToAvatarDirectionTest_update(deltaTime) { +function worldToJointDirectionTest_update(deltaTime) { var jointIndex = MyAvatar.getJointIndex("Head"); var worldDir = { x: 1, y: 0, z: 0 }; - var avatarDir = MyAvatar.worldToAvatarDirection(worldDir, jointIndex); + var avatarDir = MyAvatar.worldToJointDirection(worldDir, jointIndex); var newProperties = { linePoints: [{ x: 0, y: 0, @@ -93,42 +93,42 @@ function worldToAvatarDirectionTest_update(deltaTime) { }, avatarDir ]}; - Entities.editEntity(worldToAvatarDirectionTest_lineEntity, newProperties); + Entities.editEntity(worldToJointDirectionTest_lineEntity, newProperties); } -//worldToAvatarRotation +//worldToJointRotation // create box and parent to some player joint // convert world identity rotation to joint space rotation // each frame, update box with new orientation -var worldToAvatarRotationTest_boxEntity; -function worldToAvatarRotationTest() { +var worldToJointRotationTest_boxEntity; +function worldToJointRotationTest() { var jointIndex = MyAvatar.getJointIndex("RightHandPinky4"); var avatarPos = MyAvatar.position; var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex); var jointOffset_WorldSpace = { x: 0.0, y: 0, z: 0 }; var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace); - var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex); + var jointPosition_JointSpaceOffset = MyAvatar.worldToJointPoint(jointPosition_WorldSpaceOffset, jointIndex); var jointBoxProps = Object.create(debugBoxBaseProperties); - jointBoxProps.name = "worldToAvatarRotationTest_Box"; + jointBoxProps.name = "worldToJointRotationTest_Box"; jointBoxProps.color = { blue: 0, green: 0, red: 250 }; jointBoxProps.localPosition = jointPosition_JointSpaceOffset; jointBoxProps.parentID = AVATAR_SELF_ID; jointBoxProps.parentJointIndex = jointIndex; - worldToAvatarRotationTest_boxEntity = Entities.addEntity(jointBoxProps); + worldToJointRotationTest_boxEntity = Entities.addEntity(jointBoxProps); } -function worldToAvatarRotationTest_update(deltaTime) { +function worldToJointRotationTest_update(deltaTime) { var jointIndex = MyAvatar.getJointIndex("RightHandPinky4"); var worldRot = Quat.fromPitchYawRollDegrees(0,0,0); - var avatarRot = MyAvatar.worldToAvatarRotation(worldRot, jointIndex); + var avatarRot = MyAvatar.worldToJointRotation(worldRot, jointIndex); var newProperties = { localRotation: avatarRot }; - Entities.editEntity(worldToAvatarRotationTest_boxEntity, newProperties); + Entities.editEntity(worldToJointRotationTest_boxEntity, newProperties); } -worldToAvatarPointTest(); -worldToAvatarDirectionTest(); -worldToAvatarRotationTest(); +worldToJointPointTest(); +worldToJointDirectionTest(); +worldToJointRotationTest(); -Script.update.connect(worldToAvatarDirectionTest_update); -Script.update.connect(worldToAvatarRotationTest_update); +Script.update.connect(worldToJointDirectionTest_update); +Script.update.connect(worldToJointRotationTest_update);