KinTree.cpp
#include "KinTree.h"
#include <iostream>
#include "util/FileUtil.h"
#include "sim/RBDUtil.h"
const int cKinTree::gPosDims = 2;
const int cKinTree::gInvalidJointID = -1;
// Json keys
const std::string gJointsKey = "Joints";
const std::string gJointDescKeys[cKinTree::eJointDescMax] =
{
"Type",
"Parent",
"AttachX",
"AttachY",
"AttachZ",
"Scale",
"LinkStiffness",
"LimLow",
"LimHigh",
"Offset"
};
const std::string gBodyDefsKey = "BodyDefs";
const std::string gBodyDescKeys[cKinTree::eBodyParamMax] =
{
"Shape",
"Mass",
"AttachX",
"AttachY",
"AttachZ",
"Theta",
"Param0",
"Param1",
"Param2",
"ColorR",
"ColorG",
"ColorB",
"ColorA",
};
const std::string gDrawShapeDefsKey = "DrawShapeDefs";
const std::string gDrawShapeDescKeys[cKinTree::eDrawShapeParamMax] =
{
"Shape",
"ParentJoint",
"AttachX",
"AttachY",
"AttachZ",
"Theta",
"Param0",
"Param1",
"Param2",
"ColorR",
"ColorG",
"ColorB",
"ColorA",
};
int cKinTree::GetRoot(const Eigen::MatrixXd& joint_desc)
{
// this should always be true right?
return 0;
/*
int num_joints = GetNumJoints(joint_desc);
for (int i = 0; i < num_joints; ++i)
{
int parent = GetParent(joint_desc, i);
if (parent == gInvalidJointID)
{
return i;
}
}
assert(false);
return gInvalidJointID;
*/
}
void cKinTree::FindChildren(const Eigen::MatrixXd& joint_desc, int joint_id, Eigen::VectorXi& out_children)
{
const int max_size = 128;
int children_buffer[max_size];
int num_children = 0;
int num_joints = GetNumJoints(joint_desc);
for (int i = 0; i < num_joints; ++i)
{
int parent = GetParent(joint_desc, i);
if (parent == joint_id)
{
children_buffer[num_children] = i;
++num_children;
if (num_children >= max_size)
{
printf("Too many children, max = %i", max_size);
assert(false);
return;
}
}
}
out_children.resize(num_children);
for (int i = 0; i < num_children; ++i)
{
out_children[i] = children_buffer[i];
}
}
bool cKinTree::LoadBodyDefs(const std::string& char_file, Eigen::MatrixXd& out_body_defs)
{
bool succ = true;
std::string str;
std::ifstream f_stream(char_file.c_str());
Json::Value root;
Json::Reader reader;
succ = reader.parse(f_stream, root);
f_stream.close();
if (succ)
{
succ = false;
if (!root[gBodyDefsKey].isNull())
{
Json::Value body_defs = root.get(gBodyDefsKey, 0);
int num_bodies = body_defs.size();
succ = true;
out_body_defs.resize(num_bodies, eBodyParamMax);
for (int b = 0; b < num_bodies; ++b)
{
cKinTree::tBodyDef curr_def;
Json::Value body_json = body_defs.get(b, 0);
bool succ_def = ParseBodyDef(body_json, curr_def);
if (succ)
{
out_body_defs.row(b) = curr_def;
}
else
{
succ = false;
break;
}
}
}
}
if (!succ)
{
printf("Failed to load body definition from %s\n", char_file.c_str());
succ = false;
}
return succ;
}
bool cKinTree::ParseBodyDef(const Json::Value& root, cKinTree::tBodyDef& out_def)
{
out_def.setZero();
std::string shape_str = root.get(gBodyDescKeys[eBodyParamShape], "").asString();
eBodyShape shape;
bool succ = ParseBodyShape(shape_str, shape);
if (succ)
{
out_def(eBodyParamShape) = static_cast<double>(static_cast<int>(shape));
}
for (int i = 0; i < eBodyParamMax; ++i)
{
const std::string& curr_key = gBodyDescKeys[i];
if (!root[curr_key].isNull()
&& root[curr_key].isNumeric())
{
Json::Value json_val = root[curr_key];
double val = json_val.asDouble();
out_def(i) = val;
}
}
return succ;
}
bool cKinTree::ParseBodyShape(const std::string& str, cKinTree::eBodyShape& out_shape)
{
bool succ = true;
if (str == "box")
{
out_shape = eBodyShapeBox;
}
else if (str == "capsule")
{
out_shape = eBodyShapeCapsule;
}
else if (str == "null")
{
out_shape = eBodyShapeNULL;
}
else
{
printf("Unsupported body shape %s\n", str.c_str());
assert(false);
}
return succ;
}
bool cKinTree::LoadDrawShapeDefs(const std::string& char_file, Eigen::MatrixXd& out_draw_defs)
{
bool succ = true;
std::string str;
std::ifstream f_stream(char_file.c_str());
Json::Value root;
Json::Reader reader;
succ = reader.parse(f_stream, root);
f_stream.close();
if (succ)
{
if (!root[gDrawShapeDefsKey].isNull())
{
Json::Value shape_defs = root.get(gDrawShapeDefsKey, 0);
int num_shapes = shape_defs.size();
succ = true;
out_draw_defs.resize(num_shapes, eDrawShapeParamMax);
for (int b = 0; b < num_shapes; ++b)
{
cKinTree::tDrawShapeDef curr_def;
Json::Value shape_json = shape_defs.get(b, 0);
bool succ_def = ParseDrawShapeDef(shape_json, curr_def);
if (succ)
{
out_draw_defs.row(b) = curr_def;
}
else
{
succ = false;
break;
}
}
}
}
if (!succ)
{
printf("Failed to load draw shape definition from %s\n", char_file.c_str());
assert(false);
}
return succ;
}
bool cKinTree::ParseDrawShapeDef(const Json::Value& root, tBodyDef& out_def)
{
out_def.setZero();
std::string shape_str = root.get(gDrawShapeDescKeys[eDrawShapeShape], "").asString();
eBodyShape shape;
bool succ = ParseBodyShape(shape_str, shape);
if (succ)
{
out_def(eDrawShapeShape) = static_cast<double>(static_cast<int>(shape));
}
for (int i = 0; i < eDrawShapeParamMax; ++i)
{
const std::string& curr_key = gDrawShapeDescKeys[i];
if (!root[curr_key].isNull()
&& root[curr_key].isNumeric())
{
Json::Value json_val = root[curr_key];
double val = json_val.asDouble();
out_def(i) = val;
}
}
return succ;
}
tVector cKinTree::CalcBodyPartPos(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, const Eigen::MatrixXd& body_defs, int part_id)
{
assert(IsValidBody(body_defs, part_id));
tMatrix body_joint_trans = BodyJointTrans(body_defs, part_id);
tMatrix joint_to_world_trans = JointWorldTrans(joint_mat, state, part_id);
tVector attach_pt = tVector(0, 0, 0, 1);
attach_pt = joint_to_world_trans * (body_joint_trans * attach_pt);
return attach_pt;
}
cKinTree::eBodyShape cKinTree::GetBodyShape(const Eigen::MatrixXd& body_defs, int part_id)
{
cKinTree::eBodyShape shape = static_cast<cKinTree::eBodyShape>(static_cast<int>(body_defs(part_id, cKinTree::eBodyParamShape)));
return shape;
}
tVector cKinTree::GetBodyAttachPt(const Eigen::MatrixXd& body_defs, int part_id)
{
const cKinTree::tBodyDef& def = body_defs.row(part_id);
tVector attach_pt = tVector(def(eBodyParamAttachX), def(eBodyParamAttachY), def(eBodyParamAttachZ), 0);
return attach_pt;
}
void cKinTree::GetBodyRotation(const Eigen::MatrixXd& body_defs, int part_id, tVector& out_axis, double& out_theta)
{
const cKinTree::tBodyDef& def = body_defs.row(part_id);
out_theta = def(eBodyParamTheta);
out_axis = tVector(0, 0, 1, 0);
}
double cKinTree::GetBodyMass(const Eigen::MatrixXd& body_defs, int part_id)
{
double mass = body_defs(part_id, cKinTree::eBodyParamMass);
return mass;
}
tVector cKinTree::GetBodySize(const Eigen::MatrixXd& body_defs, int part_id)
{
const tBodyDef& def = body_defs.row(part_id);
tVector size = tVector(def(eBodyParam0), def(eBodyParam1), def(eBodyParam2), 0);
return size;
}
tVector cKinTree::GetBodyColor(const Eigen::MatrixXd& body_defs, int part_id)
{
const tBodyDef& def = body_defs.row(part_id);
tVector col = tVector(def(eBodyColorR), def(eBodyColorG), def(eBodyColorB), def(eBodyColorA));
return col;
}
double cKinTree::CalcTotalMass(const Eigen::MatrixXd& body_defs)
{
double total_mass = 0;
for (int i = 0; i < body_defs.rows(); ++i)
{
if (IsValidBody(body_defs, i))
{
double mass = cKinTree::GetBodyMass(body_defs, i);
total_mass += mass;
}
}
return total_mass;
}
bool cKinTree::IsValidBody(const Eigen::MatrixXd& body_defs, int part_id)
{
eBodyShape shape = GetBodyShape(body_defs, part_id);
if (shape < eBodyShapeMax)
{
return true;
}
return false;
}
tVector cKinTree::GetBodyLocalCoM(const Eigen::MatrixXd& body_defs, int part_id)
{
eBodyShape shape = GetBodyShape(body_defs, part_id);
tVector com = tVector::Zero();
switch (shape)
{
case eBodyShapeBox:
com.setZero();
break;
case eBodyShapeCapsule:
com.setZero();
break;
default:
assert(false); // unsupported
break;
}
return com;
}
int cKinTree::GetDrawShapeParentJoint(const tDrawShapeDef& shape)
{
return static_cast<int>(shape[eDrawShapeParentJoint]);
}
tVector cKinTree::GetDrawShapeAttachPt(const tDrawShapeDef& shape)
{
return tVector(shape[cKinTree::eDrawShapeAttachX], shape[cKinTree::eDrawShapeAttachY], shape[cKinTree::eDrawShapeAttachZ], 0);
}
void cKinTree::GetDrawShapeRotation(const tDrawShapeDef& shape, tVector& out_axis, double& out_theta)
{
out_theta = shape[cKinTree::eDrawShapeTheta];
out_axis = tVector(0, 0, 1, 0);
}
tVector cKinTree::GetDrawShapeColor(const tDrawShapeDef& shape)
{
return tVector(shape[cKinTree::eDrawShapeColorR], shape[cKinTree::eDrawShapeColorG], shape[cKinTree::eDrawShapeColorB], shape[cKinTree::eDrawShapeColorA]);
}
void cKinTree::CalcBodyPartRotation(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, const Eigen::MatrixXd& body_defs, int part_id, tVector& out_axis, double& out_theta)
{
tMatrix mat = BodyWorldTrans(joint_mat, state, body_defs, part_id);
cMathUtil::RotMatToAxisAngle(mat, out_axis, out_theta);
}
bool cKinTree::Load(const Json::Value& root, Eigen::MatrixXd& out_joint_mat)
{
bool succ = false;
if (!root[gJointsKey].isNull())
{
Json::Value joints = root[gJointsKey];
int num_joints = joints.size();
out_joint_mat.resize(num_joints, eJointDescMax);
for (int j = 0; j < num_joints; ++j)
{
tJointDesc curr_joint_desc = tJointDesc::Zero();
Json::Value joint_json = joints.get(j, 0);
succ = ParseJoint(joint_json, curr_joint_desc);
if (succ)
{
out_joint_mat.row(j) = curr_joint_desc;
}
else
{
printf("Failed to parse joint %i\n", j);
return false;
}
}
for (int j = 0; j < num_joints; ++j)
{
const auto& curr_desc = out_joint_mat.row(j);
int parent_id = static_cast<int>(curr_desc(eJointDescParent));
if (parent_id >= j)
{
printf("Parent id must be < child id, parent id: %i, child id: %i\n", parent_id, j);
out_joint_mat.resize(0, 0);
assert(false);
return false;
}
out_joint_mat.row(j) = curr_desc;
}
PostProcessJointMat(out_joint_mat);
}
return succ;
}
bool cKinTree::HasValidRoot(const Eigen::MatrixXd& joint_desc)
{
int root = GetRoot(joint_desc);
return root != gInvalidJointID;
}
tVector cKinTree::GetRootPos(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state)
{
int root = GetRoot(joint_mat);
tVector pos = GetJointOffset(joint_mat, state, root);
return pos;
}
void cKinTree::SetRootPos(const Eigen::MatrixXd& joint_mat, const tVector& pos, Eigen::VectorXd& out_state)
{
int root = GetRoot(joint_mat);
SetJointOffset(joint_mat, root, pos, out_state);
}
void cKinTree::SetRootPosX(const Eigen::MatrixXd& joint_mat, double x, Eigen::VectorXd& out_state)
{
tVector pos = GetRootPos(joint_mat, out_state);
pos[0] = x;
SetRootPos(joint_mat, pos, out_state);
}
double cKinTree::GetRootTheta(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state)
{
int root_id = GetRoot(joint_mat);
double theta = GetJointTheta(joint_mat, state, root_id);
return theta;
}
void cKinTree::SetRootTheta(const Eigen::MatrixXd& joint_mat, double theta, Eigen::VectorXd& out_state)
{
int root = GetRoot(joint_mat);
SetJointTheta(joint_mat, root, theta, out_state);
}
tVector cKinTree::CalcJointWorldPos(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tVector pos = LocalToWorldPos(joint_mat, state, joint_id, tVector::Zero());
return pos;
}
tVector cKinTree::CalcJointWorldVel(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, const Eigen::VectorXd& vel, int joint_id)
{
return CalcWorldVel(joint_mat, state, vel, joint_id, tVector::Zero());
}
tVector cKinTree::CalcWorldVel(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, const Eigen::VectorXd& vel, int parent_id, const tVector& attach_pt)
{
cSpAlg::tSpVec sv = cRBDUtil::CalcWorldVel(joint_mat, state, vel, parent_id, attach_pt);
tVector pos = cKinTree::LocalToWorldPos(joint_mat, state, parent_id, attach_pt);
cSpAlg::tSpTrans world_to_pt = cSpAlg::BuildTrans(pos);
sv = cSpAlg::ApplyTransM(world_to_pt, sv);
return cSpAlg::GetV(sv);
}
tVector cKinTree::LocalToWorldPos(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int parent_id, const tVector& attach_pt)
{
tMatrix local_to_world_trans = JointWorldTrans(joint_mat, state, parent_id);
tVector pos = attach_pt;
pos[3] = 1;
pos = local_to_world_trans * pos;
pos[3] = 0;
return pos;
}
void cKinTree::CalcJointWorldTheta(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id,
tVector& out_axis, double& out_theta)
{
int parent_id = GetParent(joint_mat, joint_id);
double theta = GetJointTheta(joint_mat, state, joint_id);
out_theta = LocalToWorldTheta(joint_mat, state, parent_id, theta);
out_axis = tVector(0, 0, 1, 0);
}
double cKinTree::LocalToWorldTheta(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int parent_id, double local_theta)
{
// assumes 2d and joint axis along z
int curr_id = parent_id;
double curr_theta = local_theta;
while (curr_id != gInvalidJointID)
{
double theta = GetJointTheta(joint_mat, state, curr_id);
curr_theta += theta;
curr_id = GetParent(joint_mat, curr_id);
}
return curr_theta;
}
int cKinTree::GetNumJoints(const Eigen::MatrixXd& joint_mat)
{
return static_cast<int>(joint_mat.rows());
}
int cKinTree::GetNumDof(const Eigen::MatrixXd& joint_mat)
{
int num_joints = GetNumJoints(joint_mat);
int num_dof = cKinTree::GetParamOffset(joint_mat, num_joints - 1) + cKinTree::GetParamSize(joint_mat, num_joints - 1);
#if !defined(DISABLE_LINK_SCALE)
num_dof += num_joints;
#endif
return num_dof;
}
void cKinTree::ApplyStep(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& step, Eigen::VectorXd& out_pose)
{
int root_id = GetRoot(joint_mat);
int num_joints = cKinTree::GetNumJoints(joint_mat);
out_pose += step;
#if !defined(DISABLE_LINK_SCALE)
int idx_offset = gPosDims + num_joints;
out_joint_mat.col(eJointDescScale) += step.block(idx_offset, 0, num_joints, 1);
// no scaling for root
out_pose(idx_offset + root_id) = 1;
#endif
}
Eigen::VectorXi cKinTree::FindJointChain(const Eigen::MatrixXd& joint_mat, int joint_beg, int joint_end)
{
Eigen::VectorXi chain;
const int max_length = 128;
int chain_buffer[max_length];
int buffer_idx = 0;
if (joint_beg == joint_end)
{
Eigen::VectorXi chain(1);
chain[0] = joint_beg;
}
int common_ancestor = gInvalidJointID;
int curr_id = joint_beg;
int end_len = 0;
while (curr_id != gInvalidJointID)
{
chain_buffer[buffer_idx] = curr_id;
++buffer_idx;
if (buffer_idx >= max_length)
{
printf("Exceeded maximum chain length %i\n", max_length);
assert(false);
return chain;
}
bool is_ancestor = IsAncestor(joint_mat, joint_end, curr_id, end_len);
if (is_ancestor)
{
common_ancestor = curr_id;
break;
}
else
{
curr_id = GetParent(joint_mat, curr_id);
}
}
bool found = common_ancestor != gInvalidJointID;
// tree should always connected?
assert(found);
if (found)
{
chain.resize(buffer_idx + end_len);
for (int i = 0; i < buffer_idx; ++i)
{
chain[i] = chain_buffer[i];
}
int idx = buffer_idx;
curr_id = joint_end;
while (curr_id != common_ancestor)
{
chain[idx] = curr_id;
curr_id = GetParent(joint_mat, curr_id);
++idx;
}
int num_flips = static_cast<int>(chain.size()) - buffer_idx;
chain.block(buffer_idx, 0, num_flips, 1).reverseInPlace();
}
return chain;
}
bool cKinTree::IsAncestor(const Eigen::MatrixXd& joint_mat, int child_joint, int ancestor_joint, int& out_len)
{
int curr_id = child_joint;
out_len = 0;
while (curr_id != gInvalidJointID)
{
if (curr_id == ancestor_joint)
{
return true;
}
else
{
curr_id = GetParent(joint_mat, curr_id);
++out_len;
}
}
return false;
}
double cKinTree::CalcChainLength(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXi& chain)
{
double len = 0;
int num_joints = static_cast<int>(chain.size());
for (int i = 1; i < num_joints; ++i)
{
int curr_id = chain(i);
int prev_id = chain(i - 1);
if (prev_id != gInvalidJointID)
{
int prev_parent = GetParent(joint_mat, prev_id);
bool is_parent = (prev_parent == curr_id);
if (is_parent)
{
double curr_len = CalcLinkLength(joint_mat, prev_id);
len += curr_len;
}
}
if (curr_id != gInvalidJointID)
{
int curr_parent = GetParent(joint_mat, curr_id);
bool is_child = (curr_parent == prev_id);
if (is_child)
{
double curr_len = CalcLinkLength(joint_mat, curr_id);
len += curr_len;
}
}
}
return len;
}
void cKinTree::CalcAABB(const Eigen::MatrixXd& joint_desc, const Eigen::VectorXd& state, tVector& out_min, tVector& out_max)
{
out_min[0] = std::numeric_limits<double>::infinity();
out_min[1] = std::numeric_limits<double>::infinity();
out_min[2] = std::numeric_limits<double>::infinity();
out_max[0] = -std::numeric_limits<double>::infinity();
out_max[1] = -std::numeric_limits<double>::infinity();
out_max[2] = -std::numeric_limits<double>::infinity();
for (int i = 0; i < GetNumJoints(joint_desc); ++i)
{
tVector pos = CalcJointWorldPos(joint_desc, state, i);
out_min = out_min.cwiseMin(pos);
out_max = out_max.cwiseMax(pos);
}
}
int cKinTree::GetParamOffset(const Eigen::MatrixXd& joint_mat, int joint_id)
{
int offset = static_cast<int>(joint_mat(joint_id, eJointDescParamOffset));
return offset;
}
int cKinTree::GetParamSize(const Eigen::MatrixXd& joint_mat, int joint_id)
{
int size = 0;
eJointType j_type = cKinTree::GetJointType(joint_mat, joint_id);
bool is_root = cKinTree::IsRoot(joint_mat, joint_id);
switch (j_type)
{
case eJointTypeRevolute:
size = 1;
break;
case eJointTypePrismatic:
size = 1;
break;
case eJointTypePlanar:
size = 3;
break;
case eJointTypeFixed:
size = (is_root) ? 3 : 0;
break;
default:
break;
}
return size;
}
Eigen::VectorXd cKinTree::GetJointParams(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int j)
{
int offset = cKinTree::GetParamOffset(joint_mat, j);
int dim = cKinTree::GetParamSize(joint_mat, j);
Eigen::VectorXd q;
if (dim > 0)
{
q = state.block(offset, 0, dim, 1);
}
else
{
q = Eigen::VectorXd::Zero(1);
}
return q;
}
void cKinTree::SetJointParams(const Eigen::MatrixXd& joint_mat, int j, const Eigen::VectorXd& params, Eigen::VectorXd& out_state)
{
int offset = cKinTree::GetParamOffset(joint_mat, j);
int dim = cKinTree::GetParamSize(joint_mat, j);
assert(dim == params.size());
out_state.block(offset, 0, dim, 1) = params;
}
cKinTree::eJointType cKinTree::GetJointType(const Eigen::MatrixXd& joint_mat, int joint_id)
{
eJointType type = static_cast<eJointType>(static_cast<int>(joint_mat(joint_id, cKinTree::eJointDescType)));
return type;
}
int cKinTree::GetParent(const Eigen::MatrixXd& joint_mat, int joint_id)
{
int parent = static_cast<int>(joint_mat(joint_id, cKinTree::eJointDescParent));
assert(parent < joint_id); // joints should always be ordered as such
// since some algorithms will assume this ordering
return parent;
}
bool cKinTree::HasParent(const Eigen::MatrixXd& joint_mat, int joint_id)
{
int parent = GetParent(joint_mat, joint_id);
return parent != gInvalidJointID;
}
bool cKinTree::IsRoot(const Eigen::MatrixXd& joint_mat, int joint_id)
{
return !HasParent(joint_mat, joint_id);
}
bool cKinTree::IsJointActuated(const Eigen::MatrixXd& joint_mat, int joint_id)
{
return !IsRoot(joint_mat, joint_id);
}
tVector cKinTree::GetJointOffset(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tVector offset = tVector::Zero();
eJointType j_type = GetJointType(joint_mat, joint_id);
bool is_root = cKinTree::IsRoot(joint_mat, joint_id);
int param_offset = GetParamOffset(joint_mat, joint_id);
switch (j_type)
{
case eJointTypeRevolute:
offset.setZero();
break;
case eJointTypePlanar:
offset.segment(0, 2) = state.segment(param_offset, 2);
break;
case eJointTypePrismatic:
offset.segment(0, 1) = state.segment(param_offset, 0);
break;
case eJointTypeFixed:
offset.segment(0, 2) = (is_root) ? state.segment(param_offset, 2) : Eigen::Vector2d(0, 0);
break;
default:
assert(false); // unsupported joint
break;
}
return offset;
}
void cKinTree::SetJointOffset(const Eigen::MatrixXd& joint_mat, int joint_id, const tVector& offset, Eigen::VectorXd& out_state)
{
eJointType j_type = GetJointType(joint_mat, joint_id);
int param_offset = GetParamOffset(joint_mat, joint_id);
switch (j_type)
{
case eJointTypePrismatic:
out_state.segment(param_offset, 1) = offset.segment(0, 1);
break;
case eJointTypePlanar:
out_state.segment(param_offset, 2) = offset.segment(0, 2);
break;
case eJointTypeFixed:
// TODO not the best fix
out_state.segment(param_offset, 2) = offset.segment(0, 2);
break;
default:
assert(false && "No offset for this joint type"); // no offset for joint type
break;
}
}
double cKinTree::GetJointTheta(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
double theta = 0;
eJointType j_type = GetJointType(joint_mat, joint_id);
int param_offset = GetParamOffset(joint_mat, joint_id);
Eigen::VectorXd params = GetJointParams(joint_mat, state, joint_id);
bool is_root = cKinTree::IsRoot(joint_mat, joint_id);
switch (j_type)
{
case eJointTypeRevolute:
theta = state(param_offset);
break;
case eJointTypePrismatic:
theta = state(param_offset);
break;
case eJointTypePlanar:
theta = state(param_offset + 2);
break;
case eJointTypeFixed:
theta = (is_root) ? state(param_offset + 2) : 0;
break;
default:
assert(false); // unsupported joint
break;
}
return theta;
}
void cKinTree::SetJointTheta(const Eigen::MatrixXd& joint_mat, int joint_id, double theta, Eigen::VectorXd& out_state)
{
eJointType j_type = GetJointType(joint_mat, joint_id);
int param_offset = GetParamOffset(joint_mat, joint_id);
switch (j_type)
{
case eJointTypeRevolute:
out_state(param_offset) = theta;
break;
case eJointTypePrismatic:
out_state(param_offset) = theta;
break;
case eJointTypePlanar:
out_state(param_offset + 2) = theta;
break;
default:
assert(false); // no offset for joint type
break;
}
}
double cKinTree::GetJointLimLow(const Eigen::MatrixXd& joint_mat, int joint_id)
{
return joint_mat(joint_id, cKinTree::eJointDescLimLow);
}
double cKinTree::GetJointLimHigh(const Eigen::MatrixXd& joint_mat, int joint_id)
{
return joint_mat(joint_id, cKinTree::eJointDescLimHigh);
}
double cKinTree::CalcLinkLength(const Eigen::MatrixXd& joint_mat, int joint_id)
{
tVector attach_pt = GetScaledAttachPt(joint_mat, joint_id);
bool is_root = IsRoot(joint_mat, joint_id);
double len = (is_root) ? 0 : attach_pt.norm();
return len;
}
tVector cKinTree::GetScaledAttachPt(const Eigen::MatrixXd& joint_mat, int joint_id)
{
tVector attach_pt = tVector(joint_mat(joint_id, cKinTree::eJointDescAttachX),
joint_mat(joint_id, cKinTree::eJointDescAttachY),
joint_mat(joint_id, cKinTree::eJointDescAttachZ), 0);
double link_scale = GetLinkScale(joint_mat, joint_id);
return attach_pt * link_scale;
}
double cKinTree::GetLinkScale(const Eigen::MatrixXd& joint_mat, int joint_id)
{
double scale = joint_mat(joint_id, eJointDescScale);
return scale;
}
void cKinTree::CalcMaxSubChainLengths(const Eigen::MatrixXd& joint_mat, Eigen::VectorXd& out_lengths)
{
int num_joints = static_cast<int>(joint_mat.rows());
out_lengths = Eigen::VectorXd::Zero(num_joints);
for (int j = num_joints - 1; j >= 0; --j)
{
int parent_id = GetParent(joint_mat, j);
if (parent_id != gInvalidJointID)
{
double curr_val = out_lengths(j);
double len = CalcLinkLength(joint_mat, j);
double& parent_val = out_lengths(parent_id);
if (parent_val < len + curr_val)
{
parent_val = len + curr_val;
}
}
}
}
void cKinTree::CalcSubTreeMasses(const Eigen::MatrixXd& joint_mat, const Eigen::MatrixXd& body_defs, Eigen::VectorXd& out_masses)
{
int num_joints = static_cast<int>(joint_mat.rows());
out_masses = Eigen::VectorXd::Zero(num_joints);
for (int j = num_joints - 1; j >= 0; --j)
{
double& curr_val = out_masses(j);
double mass = GetBodyMass(body_defs, j);
curr_val += mass;
int parent_id = GetParent(joint_mat, j);
if (parent_id != gInvalidJointID)
{
double& parent_val = out_masses(parent_id);
parent_val += curr_val;
}
}
}
bool cKinTree::ParseJoint(const Json::Value& root, tJointDesc& out_joint_desc)
{
out_joint_desc(eJointDescParent) = -1;
out_joint_desc(eJointDescScale) = 1;
out_joint_desc(eJointDescLimLow) = 1;
out_joint_desc(eJointDescLimHigh) = 0;
for (int i = 0; i < eJointDescMax; ++i)
{
const std::string& key = gJointDescKeys[i];
if (!root[key].isNull())
{
out_joint_desc[i] = root[key].asDouble();
}
}
return true;
}
void cKinTree::PostProcessJointMat(Eigen::MatrixXd& out_joint_mat)
{
int num_joints = GetNumJoints(out_joint_mat);
int offset = 0;
for (int j = 0; j < num_joints; ++j)
{
int curr_size = GetParamSize(out_joint_mat, j);
out_joint_mat(j, eJointDescParamOffset) = offset;
offset += curr_size;
}
int root_id = GetRoot(out_joint_mat);
out_joint_mat(root_id, eJointDescAttachX) = 0;
out_joint_mat(root_id, eJointDescAttachY) = 0;
out_joint_mat(root_id, eJointDescAttachZ) = 0;
}
tMatrix cKinTree::ChildParentTrans(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tMatrix mat;
eJointType j_type = cKinTree::GetJointType(joint_mat, joint_id);
switch (j_type)
{
case eJointTypeRevolute:
mat = ChildParentTransRevolute(joint_mat, state, joint_id);
break;
case eJointTypePrismatic:
mat = ChildParentTransPrismatic(joint_mat, state, joint_id);
break;
case eJointTypePlanar:
mat = ChildParentTransPlanar(joint_mat, state, joint_id);
break;
case eJointTypeFixed:
mat = ChildParentTransFixed(joint_mat, state, joint_id);
break;
default:
break;
}
return mat;
}
tMatrix cKinTree::ParentChildTrans(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tMatrix mat = ChildParentTrans(joint_mat, state, joint_id);
mat = cMathUtil::InvRigidMat(mat);
return mat;
}
tMatrix cKinTree::JointWorldTrans(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tMatrix m = tMatrix::Identity();
int curr_id = joint_id;
while (curr_id != gInvalidJointID)
{
tMatrix child_parent_mat = ChildParentTrans(joint_mat, state, curr_id);
m = child_parent_mat * m;
curr_id = GetParent(joint_mat, curr_id);
}
return m;
}
tMatrix cKinTree::WorldJointTrans(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tMatrix m = JointWorldTrans(joint_mat, state, joint_id);
m = cMathUtil::InvRigidMat(m);
return m;
}
tMatrix cKinTree::BodyWorldTrans(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, const Eigen::MatrixXd& body_defs, int part_id)
{
tMatrix body_trans = BodyJointTrans(body_defs, part_id);
tMatrix joint_trans = JointWorldTrans(joint_mat, state, part_id);
body_trans = joint_trans * body_trans;
return body_trans;
}
tMatrix cKinTree::BodyJointTrans(const Eigen::MatrixXd& body_defs, int part_id)
{
tVector attach_pt = GetBodyAttachPt(body_defs, part_id);
double theta;
tVector axis;
GetBodyRotation(body_defs, part_id, axis, theta);
tVector com = GetBodyLocalCoM(body_defs, part_id);
tMatrix rot = cMathUtil::RotateMat(axis, theta);
tMatrix trans = cMathUtil::TranslateMat(attach_pt + com);
tMatrix m = trans * rot;
return m;
}
cKinTree::tJointDesc cKinTree::BuildJointDesc(eJointType joint_type, int parent_id, const tVector& attach_pt)
{
tJointDesc desc;
desc(eJointDescType) = static_cast<double>(joint_type);
desc(eJointDescParent) = parent_id;
desc(eJointDescAttachX) = attach_pt[0];
desc(eJointDescAttachY) = attach_pt[1];
desc(eJointDescAttachZ) = attach_pt[2];
desc(eJointDescScale) = 1;
desc(eJointDescLinkStiffness) = 1;
desc(eJointDescLimLow) = 1;
desc(eJointDescLimHigh) = 0;
desc(eJointDescParamOffset) = 0;
return desc;
}
tMatrix cKinTree::ChildParentTransRevolute(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tVector attach_pt = GetScaledAttachPt(joint_mat, joint_id);
double theta = GetJointTheta(joint_mat, state, joint_id);
tMatrix R = cMathUtil::RotateMat(tVector(0, 0, 1, 0), theta);
tMatrix T = cMathUtil::TranslateMat(attach_pt);
tMatrix mat = T * R;
return mat;
}
tMatrix cKinTree::ChildParentTransPlanar(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
bool is_root = cKinTree::IsRoot(joint_mat, joint_id);
tVector attach_pt = GetScaledAttachPt(joint_mat, joint_id);
double theta = GetJointTheta(joint_mat, state, joint_id);
tVector offset = GetJointOffset(joint_mat, state, joint_id);
tMatrix R = cMathUtil::RotateMat(tVector(0, 0, 1, 0), theta);
tMatrix T0 = cMathUtil::TranslateMat(attach_pt);
tMatrix T1 = cMathUtil::TranslateMat(offset);
tMatrix mat;
if (is_root)
{
mat = T0 * T1 * R;
}
else
{
mat = T0 * R * T1;
}
return mat;
}
tMatrix cKinTree::ChildParentTransFixed(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
bool is_root = cKinTree::IsRoot(joint_mat, joint_id);
tVector attach_pt = GetScaledAttachPt(joint_mat, joint_id);
double theta = GetJointTheta(joint_mat, state, joint_id);
tVector offset = GetJointOffset(joint_mat, state, joint_id);
tMatrix R = cMathUtil::RotateMat(tVector(0, 0, 1, 0), theta);
tMatrix T0 = cMathUtil::TranslateMat(attach_pt);
tMatrix T1 = cMathUtil::TranslateMat(offset);
tMatrix mat;
if (is_root)
{
mat = T0 * T1 * R;
}
else
{
mat = T0;
}
return mat;
}
tMatrix cKinTree::ChildParentTransPrismatic(const Eigen::MatrixXd& joint_mat, const Eigen::VectorXd& state, int joint_id)
{
tVector attach_pt = GetScaledAttachPt(joint_mat, joint_id);
double theta = GetJointTheta(joint_mat, state, joint_id);
tVector offset = tVector(0, theta, 0, 0);
tMatrix R = cMathUtil::RotateMat(tVector(0, 0, 1, 0), 0);
tMatrix T0 = cMathUtil::TranslateMat(attach_pt);
tMatrix T1 = cMathUtil::TranslateMat(offset);
tMatrix mat = T0 * R * T1;
return mat;
}