30 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
36 for (i = 1; i < model.mBodies.size(); i++) {
37 unsigned int q_index = model.mJoints[i].q_index;
38 unsigned int lambda = model.lambda[i];
40 jcalc (model, i, Q, QDot);
43 model.X_base[i] = model.X_lambda[i] * model.X_base[lambda];
44 model.v[i] = model.X_lambda[i].apply(model.v[lambda]) + model.v_J[i];
46 model.X_base[i] = model.X_lambda[i];
47 model.v[i] = model.v_J[i];
50 model.c[i] = model.c_J[i] +
crossm(model.v[i],model.v_J[i]);
51 model.a[i] = model.X_lambda[i].apply(model.a[lambda]) + model.c[i];
53 if(model.mJoints[i].mJointType != JointTypeCustom){
54 if (model.mJoints[i].mDoFCount == 1) {
55 model.a[i] = model.a[i] + model.S[i] * QDDot[q_index];
56 }
else if (model.mJoints[i].mDoFCount == 3) {
57 Vector3d omegadot_temp (QDDot[q_index],
60 model.a[i] = model.a[i] + model.multdof3_S[i] * omegadot_temp;
63 unsigned int custom_index = model.mJoints[i].custom_joint_index;
64 const CustomJoint* custom_joint = model.mCustomJoints[custom_index];
65 unsigned int joint_dof_count = custom_joint->mDoFCount;
67 model.a[i] = model.a[i]
68 + ( model.mCustomJoints[custom_index]->S
69 * QDDot.
block(q_index, 0, joint_dof_count, 1));
73 for (i = 1; i < model.mBodies.size(); i++) {
74 LOG <<
"a[" << i <<
"] = " << model.a[i].transpose() << std::endl;
83 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
88 for (i = 1; i < model.mBodies.size(); i++) {
89 unsigned int lambda = model.lambda[i];
93 jcalc (model, i, (*Q), QDot_zero);
96 model.X_base[i] = model.X_lambda[i] * model.X_base[lambda];
98 model.X_base[i] = model.X_lambda[i];
104 for (i = 1; i < model.mBodies.size(); i++) {
105 unsigned int lambda = model.lambda[i];
107 jcalc (model, i, *Q, *QDot);
110 model.v[i] = model.X_lambda[i].apply(model.v[lambda]) + model.v_J[i];
111 model.c[i] = model.c_J[i] +
crossm(model.v[i],model.v_J[i]);
113 model.v[i] = model.v_J[i];
114 model.c[i] = model.c_J[i] +
crossm(model.v[i],model.v_J[i]);
122 for (i = 1; i < model.mBodies.size(); i++) {
123 unsigned int q_index = model.mJoints[i].q_index;
125 unsigned int lambda = model.lambda[i];
128 model.a[i] = model.X_lambda[i].apply(model.a[lambda]) + model.c[i];
130 model.a[i] = model.c[i];
133 if( model.mJoints[i].mJointType != JointTypeCustom){
134 if (model.mJoints[i].mDoFCount == 1) {
135 model.a[i] = model.a[i] + model.S[i] * (*QDDot)[q_index];
136 }
else if (model.mJoints[i].mDoFCount == 3) {
137 Vector3d omegadot_temp ((*QDDot)[q_index],
138 (*QDDot)[q_index + 1],
139 (*QDDot)[q_index + 2]);
140 model.a[i] = model.a[i]
141 + model.multdof3_S[i] * omegadot_temp;
144 unsigned int k = model.mJoints[i].custom_joint_index;
146 const CustomJoint* custom_joint = model.mCustomJoints[k];
147 unsigned int joint_dof_count = custom_joint->mDoFCount;
149 model.a[i] = model.a[i]
150 + ( (model.mCustomJoints[k]->S)
151 *(QDDot->
block(q_index, 0, joint_dof_count, 1)));
160 unsigned int body_id,
161 const Vector3d &point_body_coordinates,
162 bool update_kinematics) {
164 if (update_kinematics) {
168 if (body_id >= model.fixed_body_discriminator) {
169 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
170 unsigned int parent_id = model.mFixedBodies[fbody_id].mMovableParent;
173 model.mFixedBodies[fbody_id].mParentTransform.E.transpose();
174 Vector3d fixed_position = model.mFixedBodies[fbody_id].mParentTransform.r;
176 Matrix3d parent_body_rotation = model.X_base[parent_id].E.transpose();
177 Vector3d parent_body_position = model.X_base[parent_id].r;
179 return (parent_body_position
180 + (parent_body_rotation
181 * (fixed_position + fixed_rotation * (point_body_coordinates))) );
184 Matrix3d body_rotation = model.X_base[body_id].E.transpose();
185 Vector3d body_position = model.X_base[body_id].r;
187 return body_position + body_rotation * point_body_coordinates;
193 unsigned int body_id,
194 const Vector3d &point_base_coordinates,
195 bool update_kinematics) {
196 if (update_kinematics) {
200 if (body_id >= model.fixed_body_discriminator) {
201 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
202 unsigned int parent_id = model.mFixedBodies[fbody_id].mMovableParent;
204 Matrix3d fixed_rotation = model.mFixedBodies[fbody_id].mParentTransform.E;
205 Vector3d fixed_position = model.mFixedBodies[fbody_id].mParentTransform.r;
207 Matrix3d parent_body_rotation = model.X_base[parent_id].E;
208 Vector3d parent_body_position = model.X_base[parent_id].r;
210 return (fixed_rotation
212 - parent_body_rotation
213 * (parent_body_position - point_base_coordinates)));
216 Matrix3d body_rotation = model.X_base[body_id].E;
217 Vector3d body_position = model.X_base[body_id].r;
219 return body_rotation * (point_base_coordinates - body_position);
225 const unsigned int body_id,
226 bool update_kinematics) {
228 if (update_kinematics) {
232 if (body_id >= model.fixed_body_discriminator) {
233 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
234 model.mFixedBodies[fbody_id].mBaseTransform =
235 model.mFixedBodies[fbody_id].mParentTransform
236 * model.X_base[model.mFixedBodies[fbody_id].mMovableParent];
238 return model.mFixedBodies[fbody_id].mBaseTransform.E;
241 return model.X_base[body_id].E;
247 unsigned int body_id,
250 bool update_kinematics) {
251 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
254 if (update_kinematics) {
266 assert (G.
rows() == 3 && G.
cols() == model.qdot_size );
268 unsigned int reference_body_id = body_id;
270 if (model.IsFixedBodyId(body_id)) {
271 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
272 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
275 unsigned int j = reference_body_id;
280 unsigned int q_index = model.mJoints[j].q_index;
282 if(model.mJoints[j].mJointType != JointTypeCustom){
283 if (model.mJoints[j].mDoFCount == 1) {
284 G.
block(0,q_index, 3, 1) =
286 model.X_base[j].inverse().apply(
287 model.S[j])).block<3, 1>(3,0);
288 }
else if (model.mJoints[j].mDoFCount == 3) {
289 G.
block(0, q_index, 3, 3) =
291 * model.X_base[j].
inverse()).toMatrix()
292 * model.multdof3_S[j]).block<3, 3>(3,0);
295 unsigned int k = model.mJoints[j].custom_joint_index;
297 G.
block(0, q_index, 3, model.mCustomJoints[k]->mDoFCount) =
299 * model.X_base[j].
inverse()).toMatrix()
300 * model.mCustomJoints[k]->S).block(
301 3,0,3,model.mCustomJoints[k]->mDoFCount);
311 unsigned int body_id,
314 bool update_kinematics) {
315 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
318 if (update_kinematics) {
330 assert (G.
rows() == 6 && G.
cols() == model.qdot_size );
332 unsigned int reference_body_id = body_id;
334 if (model.IsFixedBodyId(body_id)) {
335 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
336 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
339 unsigned int j = reference_body_id;
342 unsigned int q_index = model.mJoints[j].q_index;
344 if(model.mJoints[j].mJointType != JointTypeCustom){
345 if (model.mJoints[j].mDoFCount == 1) {
346 G.
block(0,q_index, 6, 1)
348 model.X_base[j].inverse().apply(
349 model.S[j])).block<6, 1>(0,0);
350 }
else if (model.mJoints[j].mDoFCount == 3) {
351 G.
block(0, q_index, 6, 3)
353 * model.X_base[j].
inverse()).toMatrix()
354 * model.multdof3_S[j]).block<6, 3>(0,0);
357 unsigned int k = model.mJoints[j].custom_joint_index;
359 G.
block(0, q_index, 6, model.mCustomJoints[k]->mDoFCount)
361 * model.X_base[j].
inverse()).toMatrix()
362 * model.mCustomJoints[k]->S).block(
363 0,0,6,model.mCustomJoints[k]->mDoFCount);
373 unsigned int body_id,
375 bool update_kinematics) {
376 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
379 if (update_kinematics) {
383 assert (G.
rows() == 6 && G.
cols() == model.qdot_size );
385 unsigned int reference_body_id = body_id;
389 if (model.IsFixedBodyId(body_id)) {
390 unsigned int fbody_id = body_id
391 - model.fixed_body_discriminator;
393 reference_body_id = model
394 .mFixedBodies[fbody_id]
397 base_to_body = model.mFixedBodies[fbody_id]
399 * model.X_base[reference_body_id];
401 base_to_body = model.X_base[reference_body_id];
404 unsigned int j = reference_body_id;
407 unsigned int q_index = model.mJoints[j].q_index;
409 if(model.mJoints[j].mJointType != JointTypeCustom){
410 if (model.mJoints[j].mDoFCount == 1) {
411 G.
block(0,q_index,6,1) =
417 }
else if (model.mJoints[j].mDoFCount == 3) {
418 G.
block(0,q_index,6,3) =
419 (base_to_body * model.X_base[j].
inverse()
420 ).toMatrix() * model.multdof3_S[j];
422 }
else if(model.mJoints[j].mJointType == JointTypeCustom) {
423 unsigned int k = model.mJoints[j].custom_joint_index;
425 G.
block(0,q_index,6,model.mCustomJoints[k]->mDoFCount ) =
426 (base_to_body * model.X_base[j].
inverse()
427 ).toMatrix() * model.mCustomJoints[k]->S;
438 unsigned int body_id,
440 bool update_kinematics) {
441 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
442 assert (model.IsBodyId(body_id) || body_id == 0);
443 assert (model.q_size == Q.
size());
444 assert (model.qdot_size == QDot.
size());
447 model.v[0].setZero();
450 if (update_kinematics) {
454 unsigned int reference_body_id = body_id;
455 Vector3d reference_point = point_position;
457 if (model.IsFixedBodyId(body_id)) {
458 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
459 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
469 reference_point).
apply(model.v[reference_body_id]);
472 point_spatial_velocity[3],
473 point_spatial_velocity[4],
474 point_spatial_velocity[5]
482 unsigned int body_id,
484 bool update_kinematics) {
485 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
486 assert (model.IsBodyId(body_id) || body_id == 0);
487 assert (model.q_size == Q.
size());
488 assert (model.qdot_size == QDot.
size());
491 model.v[0].setZero();
494 if (update_kinematics) {
498 unsigned int reference_body_id = body_id;
499 Vector3d reference_point = point_position;
501 if (model.IsFixedBodyId(body_id)) {
502 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
503 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
512 reference_point).
apply(model.v[reference_body_id]);
520 unsigned int body_id,
522 bool update_kinematics) {
523 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
526 model.v[0].setZero();
527 model.a[0].setZero();
529 if (update_kinematics)
534 unsigned int reference_body_id = body_id;
535 Vector3d reference_point = point_position;
537 if (model.IsFixedBodyId(body_id)) {
538 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
539 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
552 ).cross(
Vector3d (p_v_i[3], p_v_i[4], p_v_i[5]));
556 p_a_i[3] + a_dash[0],
557 p_a_i[4] + a_dash[1],
567 unsigned int body_id,
569 bool update_kinematics) {
570 LOG <<
"-------- " << __func__ <<
" --------" << std::endl;
573 model.v[0].setZero();
574 model.a[0].setZero();
576 if (update_kinematics)
581 unsigned int reference_body_id = body_id;
582 Vector3d reference_point = point_position;
584 if (model.IsFixedBodyId(body_id)) {
585 unsigned int fbody_id = body_id - model.fixed_body_discriminator;
586 reference_body_id = model.mFixedBodies[fbody_id].mMovableParent;
599 ).cross(
Vector3d (p_v_i[3], p_v_i[4], p_v_i[5]));
600 return (p_X_i.
apply(model.a[reference_body_id])
604#ifndef RBDL_USE_CASADI_MATH
608 const std::vector<unsigned int>& body_id,
609 const std::vector<Vector3d>& body_point,
610 const std::vector<Vector3d>& target_pos,
614 unsigned int max_iter) {
615 assert (Qinit.
size() == model.q_size);
616 assert (body_id.size() == body_point.size());
617 assert (body_id.size() == target_pos.size());
624 for (
unsigned int ik_iter = 0; ik_iter < max_iter; ik_iter++) {
627 for (
unsigned int k = 0; k < body_id.size(); k++) {
632 LOG <<
"current_pos = " << point_base.transpose() << std::endl;
634 for (
unsigned int i = 0; i < 3; i++) {
635 for (
unsigned int j = 0; j < model.qdot_size; j++) {
636 unsigned int row = k * 3 + i;
637 LOG <<
"i = " << i <<
" j = " << j <<
" k = " << k <<
" row = "
638 << row <<
" col = " << j << std::endl;
642 e[k * 3 + i] = target_pos[k][i] - point_base[i];
646 LOG <<
"J = " << J << std::endl;
647 LOG <<
"e = " << e.
transpose() << std::endl;
650 if (e.
norm() < step_tol) {
651 LOG <<
"Reached target close enough after " << ik_iter <<
" steps" << std::endl;
662 assert (solve_successful);
664 LOG <<
"z = " << z << std::endl;
667 LOG <<
"change = " << delta_theta << std::endl;
669 Qres = Qres + delta_theta;
670 LOG <<
"Qres = " << Qres.
transpose() << std::endl;
672 if (delta_theta.
norm() < step_tol) {
673 LOG <<
"reached convergence after " << ik_iter <<
" steps" << std::endl;
682 for (
unsigned int i = 0; i < z.
size(); i++) {
692 LOG <<
"test_res = " << test_res.
transpose() << std::endl;
704 Vector3d l =
Vector3d (RotMat(2,1) - RotMat(1,2), RotMat(0,2) - RotMat(2,0), RotMat(1,0) - RotMat(0,1));
706 double preFactor =
atan2(l.norm(),(RotMat.trace() - 1.0))/l.norm();
709 else if((RotMat(0,0)>0 && RotMat(1,1)>0 && RotMat(2,2) > 0) || l.norm() < tol){
713 double PI = atan(1)*4.0;
714 return Vector3d (PI/2*(RotMat(0,0) + 1.0),PI/2*(RotMat(1,1) + 1.0),PI/2*(RotMat(2,2) + 1.0));
730 unsigned int body_id,
748 unsigned int body_id,
766 unsigned int body_id,
783 unsigned int body_id,
802 unsigned int body_id,
819 unsigned int body_id,
840 for (
unsigned int i = 0; i < size; i++){
861 assert (Qinit.
size() == model.q_size);
862 assert (Qres.
size() == Qinit.
size());
873 for (
unsigned int k = 0; k < CS.
body_ids.size(); k++) {
882 for (
unsigned int i = 0; i < 3; i++){
886 for (
unsigned int j = 0; j < model.qdot_size; j++) {
893 for (
unsigned int i = 0; i < 3; i++){
896 for (
unsigned int j = 0; j < model.qdot_size; j++) {
902 for (
unsigned int i = 0; i < 3; i++){
905 for (
unsigned int j = 0; j < model.qdot_size; j++) {
911 for (
unsigned int i = 0; i < 2; i++){
914 for (
unsigned int j = 0; j < model.qdot_size; j++) {
923 for (
unsigned int j = 0; j < model.qdot_size; j++) {
929 Utils::CalcCenterOfMass (model, Qres, Qres, NULL, mass, point_base, NULL, NULL, NULL, NULL,
false);
932 for (
unsigned int i = 0; i < 2; i++){
935 for (
unsigned int j = 0; j < model.qdot_size; j++) {
941 assert (
false && !
"Invalid inverse kinematics constraint");
945 LOG <<
"J = " << CS.
J << std::endl;
946 LOG <<
"e = " << CS.
e.
transpose() << std::endl;
951 LOG <<
"Reached target close enough after " << CS.
num_steps <<
" steps" << std::endl;
974 for (
size_t ei = 0; ei < CS.
e.
size(); ei ++) {
975 Ek += CS.
e[ei] * CS.
e[ei] * 0.5;
983 for (
size_t wi = 0; wi < Qres.
size(); wi++) {
984 Wn(wi, wi) = ek[wi] * ek[wi] * 0.5 + CS.
lambda;
991 Qres = Qres + delta_theta;
994 LOG <<
"reached convergence after " << CS.
num_steps <<
" steps" << std::endl;
MX_Xd_dynamic transpose() const
unsigned int rows() const
MX_Xd_dynamic & setZero()
unsigned int cols() const
MX_Xd_dynamic squaredNorm() const
MX_Xd_dynamic norm() const
unsigned int size() const
static MX_Xd_dynamic Identity(unsigned int size, unsigned int ignoredSize=0)
static MX_Xd_dynamic Zero(unsigned int nrows, unsigned int ncols=1)
MX_Xd_SubMatrix block(unsigned int row_start, unsigned int col_start)
RBDL_DLLAPI Matrix3d CalcBodyWorldOrientation(Model &model, const VectorNd &Q, const unsigned int body_id, bool update_kinematics)
Returns the orientation of a given body as 3x3 matrix.
RBDL_DLLAPI void UpdateKinematics(Model &model, const VectorNd &Q, const VectorNd &QDot, const VectorNd &QDDot)
Updates and computes velocities and accelerations of the bodies.
RBDL_DLLAPI Vector3d CalcAngularVelocityfromMatrix(const Matrix3d &RotMat)
RBDL_DLLAPI void CalcBodySpatialJacobian(Model &model, const VectorNd &Q, unsigned int body_id, MatrixNd &G, bool update_kinematics)
Computes the spatial jacobian for a body.
RBDL_DLLAPI void CalcPointJacobian6D(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_position, MatrixNd &G, bool update_kinematics)
Computes a 6-D Jacobian for a point on a body.
RBDL_DLLAPI Vector3d CalcBodyToBaseCoordinates(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_body_coordinates, bool update_kinematics)
Returns the base coordinates of a point given in body coordinates.
RBDL_DLLAPI SpatialVector CalcPointAcceleration6D(Model &model, const VectorNd &Q, const VectorNd &QDot, const VectorNd &QDDot, unsigned int body_id, const Vector3d &point_position, bool update_kinematics)
Computes linear and angular acceleration of a point on a body.
RBDL_DLLAPI void UpdateKinematicsCustom(Model &model, const VectorNd *Q, const VectorNd *QDot, const VectorNd *QDDot)
Selectively updates model internal states of body positions, velocities and/or accelerations.
RBDL_DLLAPI void CalcPointJacobian(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_position, MatrixNd &G, bool update_kinematics)
Computes the point jacobian for a point on a body.
RBDL_DLLAPI Vector3d CalcBaseToBodyCoordinates(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_base_coordinates, bool update_kinematics)
Returns the body coordinates of a point given in base coordinates.
RBDL_DLLAPI Vector3d CalcPointVelocity(Model &model, const VectorNd &Q, const VectorNd &QDot, unsigned int body_id, const Vector3d &point_position, bool update_kinematics)
Computes the velocity of a point on a body.
RBDL_DLLAPI bool InverseKinematics(Model &model, const VectorNd &Qinit, const std::vector< unsigned int > &body_id, const std::vector< Vector3d > &body_point, const std::vector< Vector3d > &target_pos, VectorNd &Qres, double step_tol, double lambda, unsigned int max_iter)
Computes the inverse kinematics iteratively using a damped Levenberg-Marquardt method (also known as ...
RBDL_DLLAPI Math::SpatialVector CalcPointVelocity6D(Model &model, const Math::VectorNd &Q, const Math::VectorNd &QDot, unsigned int body_id, const Math::Vector3d &point_position, bool update_kinematics)
Computes angular and linear velocity of a point that is fixed on a body.
RBDL_DLLAPI Vector3d CalcPointAcceleration(Model &model, const VectorNd &Q, const VectorNd &QDot, const VectorNd &QDDot, unsigned int body_id, const Vector3d &point_position, bool update_kinematics)
Computes the linear acceleration of a point on a body.
SpatialMatrix crossm(const SpatialVector &v)
RBDL_DLLAPI bool LinSolveGaussElimPivot(MatrixNd A, VectorNd b, VectorNd &x)
Solves a linear system using gaussian elimination with pivoting.
RBDL_DLLAPI Vector3d Vector3dZero
RBDL_DLLAPI void CalcCenterOfMass(Model &model, const Math::VectorNd &q, const Math::VectorNd &qdot, const Math::VectorNd *qddot, Scalar &mass, Math::Vector3d &com, Math::Vector3d *com_velocity, Math::Vector3d *com_acceleration, Math::Vector3d *angular_momentum, Math::Vector3d *change_of_angular_momentum, bool update_kinematics)
Computes the Center of Mass (COM) and optionally its linear velocity.
RBDL_DLLAPI void jcalc(Model &model, unsigned int joint_id, const VectorNd &q, const VectorNd &qdot)
MX_Xd_scalar atan2(const MX_Xd_scalar &x, const MX_Xd_scalar &y)
unsigned int AddOrientationConstraint(unsigned int body_id, const Math::Matrix3d &target_orientation, float weight=1.)
std::vector< Math::Vector3d > target_positions
@ ConstraintTypePositionCoMXY
@ ConstraintTypePositionZ
@ ConstraintTypePositionXY
@ ConstraintTypeOrientation
InverseKinematicsConstraintSet()
std::vector< unsigned int > body_ids
Math::MatrixNd G
the Jacobian of all constraints
unsigned int num_constraints
Vector with all the constraint residuals.
std::vector< Math::Vector3d > body_points
unsigned int AddPointConstraintCoMXY(unsigned int body_id, const Math::Vector3d &target_pos, float weight=1.)
unsigned int ClearConstraints()
std::vector< float > constraint_weight
unsigned int num_steps
Damping factor, the default value of 1.0e-6 is reasonable for most problems.
unsigned int AddPointConstraint(unsigned int body_id, const Math::Vector3d &body_point, const Math::Vector3d &target_pos, float weight=1.)
std::vector< unsigned int > constraint_row_index
unsigned int AddPointConstraintZ(unsigned int body_id, const Math::Vector3d &body_point, const Math::Vector3d &target_pos, float weight=1.)
std::vector< Math::Matrix3d > target_orientations
unsigned int AddPointConstraintXY(unsigned int body_id, const Math::Vector3d &body_point, const Math::Vector3d &target_pos, float weight=1.)
Math::VectorNd e
temporary storage of a single body Jacobian
unsigned int AddFullConstraint(unsigned int body_id, const Math::Vector3d &body_point, const Math::Vector3d &target_pos, const Math::Matrix3d &target_orientation, float weight=1.)
std::vector< ConstraintType > constraint_type
Compact representation of spatial transformations.
SpatialVector apply(const SpatialVector &v_sp)
SpatialTransform inverse() const