Blender  V2.59
IK_QTask.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: IK_QTask.cpp 38232 2011-07-08 12:18:54Z blendix $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Original Author: Laurence
00025  * Contributor(s): Brecht
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include "IK_QTask.h"
00036 
00037 // IK_QTask
00038 
00039 IK_QTask::IK_QTask(
00040         int size,
00041         bool primary,
00042         bool active,
00043         const IK_QSegment *segment
00044 ) :
00045         m_size(size), m_primary(primary), m_active(active), m_segment(segment),
00046         m_weight(1.0)
00047 {
00048 }
00049 
00050 // IK_QPositionTask
00051 
00052 IK_QPositionTask::IK_QPositionTask(
00053         bool primary,
00054         const IK_QSegment *segment,
00055         const MT_Vector3& goal
00056 ) :
00057         IK_QTask(3, primary, true, segment), m_goal(goal)
00058 {
00059         // computing clamping length
00060         int num;
00061         const IK_QSegment *seg;
00062 
00063         m_clamp_length = 0.0;
00064         num = 0;
00065 
00066         for (seg = m_segment; seg; seg = seg->Parent()) {
00067                 m_clamp_length += seg->MaxExtension();
00068                 num++;
00069         }
00070 
00071         m_clamp_length /= 2*num;
00072 }
00073 
00074 void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian)
00075 {
00076         // compute beta
00077         const MT_Vector3& pos = m_segment->GlobalEnd();
00078 
00079         MT_Vector3 d_pos = m_goal - pos;
00080         MT_Scalar length = d_pos.length();
00081 
00082         if (length > m_clamp_length)
00083                 d_pos = (m_clamp_length/length)*d_pos;
00084         
00085         jacobian.SetBetas(m_id, m_size, m_weight*d_pos);
00086 
00087         // compute derivatives
00088         int i;
00089         const IK_QSegment *seg;
00090 
00091         for (seg = m_segment; seg; seg = seg->Parent()) {
00092                 MT_Vector3 p = seg->GlobalStart() - pos;
00093 
00094                 for (i = 0; i < seg->NumberOfDoF(); i++) {
00095                         MT_Vector3 axis = seg->Axis(i)*m_weight;
00096 
00097                         if (seg->Translational())
00098                                 jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis, 1e2);
00099                         else {
00100                                 MT_Vector3 pa = p.cross(axis);
00101                                 jacobian.SetDerivatives(m_id, seg->DoFId()+i, pa, 1e0);
00102                         }
00103                 }
00104         }
00105 }
00106 
00107 MT_Scalar IK_QPositionTask::Distance() const
00108 {
00109         const MT_Vector3& pos = m_segment->GlobalEnd();
00110         MT_Vector3 d_pos = m_goal - pos;
00111         return d_pos.length();
00112 }
00113 
00114 // IK_QOrientationTask
00115 
00116 IK_QOrientationTask::IK_QOrientationTask(
00117         bool primary,
00118         const IK_QSegment *segment,
00119         const MT_Matrix3x3& goal
00120 ) :
00121         IK_QTask(3, primary, true, segment), m_goal(goal), m_distance(0.0)
00122 {
00123 }
00124 
00125 void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian)
00126 {
00127         // compute betas
00128         const MT_Matrix3x3& rot = m_segment->GlobalTransform().getBasis();
00129 
00130         MT_Matrix3x3 d_rotm = m_goal*rot.transposed();
00131         d_rotm.transpose();
00132 
00133         MT_Vector3 d_rot;
00134         d_rot = -0.5*MT_Vector3(d_rotm[2][1] - d_rotm[1][2],
00135                                 d_rotm[0][2] - d_rotm[2][0],
00136                                 d_rotm[1][0] - d_rotm[0][1]);
00137 
00138         m_distance = d_rot.length();
00139 
00140         jacobian.SetBetas(m_id, m_size, m_weight*d_rot);
00141 
00142         // compute derivatives
00143         int i;
00144         const IK_QSegment *seg;
00145 
00146         for (seg = m_segment; seg; seg = seg->Parent())
00147                 for (i = 0; i < seg->NumberOfDoF(); i++) {
00148 
00149                         if (seg->Translational())
00150                                 jacobian.SetDerivatives(m_id, seg->DoFId()+i, MT_Vector3(0, 0, 0), 1e2);
00151                         else {
00152                                 MT_Vector3 axis = seg->Axis(i)*m_weight;
00153                                 jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis, 1e0);
00154                         }
00155                 }
00156 }
00157 
00158 // IK_QCenterOfMassTask
00159 // Note: implementation not finished!
00160 
00161 IK_QCenterOfMassTask::IK_QCenterOfMassTask(
00162         bool primary,
00163         const IK_QSegment *segment,
00164         const MT_Vector3& goal_center
00165 ) :
00166         IK_QTask(3, primary, true, segment), m_goal_center(goal_center)
00167 {
00168         m_total_mass_inv = ComputeTotalMass(m_segment);
00169         if (!MT_fuzzyZero(m_total_mass_inv))
00170                 m_total_mass_inv = 1.0/m_total_mass_inv;
00171 }
00172 
00173 MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment)
00174 {
00175         MT_Scalar mass = /*seg->Mass()*/ 1.0;
00176 
00177         const IK_QSegment *seg;
00178         for (seg = segment->Child(); seg; seg = seg->Sibling())
00179                 mass += ComputeTotalMass(seg);
00180         
00181         return mass;
00182 }
00183 
00184 MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment)
00185 {
00186         MT_Vector3 center = /*seg->Mass()**/segment->GlobalStart();
00187 
00188         const IK_QSegment *seg;
00189         for (seg = segment->Child(); seg; seg = seg->Sibling())
00190                 center += ComputeCenter(seg);
00191         
00192         return center;
00193 }
00194 
00195 void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment)
00196 {
00197         int i;
00198         MT_Vector3 p = center - segment->GlobalStart();
00199 
00200         for (i = 0; i < segment->NumberOfDoF(); i++) {
00201                 MT_Vector3 axis = segment->Axis(i)*m_weight;
00202                 axis *= /*segment->Mass()**/m_total_mass_inv;
00203                 
00204                 if (segment->Translational())
00205                         jacobian.SetDerivatives(m_id, segment->DoFId()+i, axis, 1e2);
00206                 else {
00207                         MT_Vector3 pa = axis.cross(p);
00208                         jacobian.SetDerivatives(m_id, segment->DoFId()+i, pa, 1e0);
00209                 }
00210         }
00211         
00212         const IK_QSegment *seg;
00213         for (seg = segment->Child(); seg; seg = seg->Sibling())
00214                 JacobianSegment(jacobian, center, seg);
00215 }
00216 
00217 void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian)
00218 {
00219         MT_Vector3 center = ComputeCenter(m_segment)*m_total_mass_inv;
00220 
00221         // compute beta
00222         MT_Vector3 d_pos = m_goal_center - center;
00223 
00224         m_distance = d_pos.length();
00225 
00226 #if 0
00227         if (m_distance > m_clamp_length)
00228                 d_pos = (m_clamp_length/m_distance)*d_pos;
00229 #endif
00230         
00231         jacobian.SetBetas(m_id, m_size, m_weight*d_pos);
00232 
00233         // compute derivatives
00234         JacobianSegment(jacobian, center, m_segment);
00235 }
00236 
00237 MT_Scalar IK_QCenterOfMassTask::Distance() const
00238 {
00239         return m_distance;
00240 }
00241