Blender  V2.59
IK_Solver.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: IK_Solver.cpp 35154 2011-02-25 11:43:19Z jesterking $
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 "../extern/IK_solver.h"
00036 
00037 #include "IK_QJacobianSolver.h"
00038 #include "IK_QSegment.h"
00039 #include "IK_QTask.h"
00040 
00041 #include <list>
00042 using namespace std;
00043 
00044 class IK_QSolver {
00045 public:
00046         IK_QSolver() : root(NULL) {};
00047 
00048         IK_QJacobianSolver solver;
00049         IK_QSegment *root;
00050         std::list<IK_QTask*> tasks;
00051 };
00052 
00053 // FIXME: locks still result in small "residual" changes to the locked axes...
00054 IK_QSegment *CreateSegment(int flag, bool translate)
00055 {
00056         int ndof = 0;
00057         ndof += (flag & IK_XDOF)? 1: 0;
00058         ndof += (flag & IK_YDOF)? 1: 0;
00059         ndof += (flag & IK_ZDOF)? 1: 0;
00060 
00061         IK_QSegment *seg;
00062 
00063         if (ndof == 0)
00064                 return NULL;
00065         else if (ndof == 1) {
00066                 int axis;
00067 
00068                 if (flag & IK_XDOF) axis = 0;
00069                 else if (flag & IK_YDOF) axis = 1;
00070                 else axis = 2;
00071 
00072                 if (translate)
00073                         seg = new IK_QTranslateSegment(axis);
00074                 else
00075                         seg = new IK_QRevoluteSegment(axis);
00076         }
00077         else if (ndof == 2) {
00078                 int axis1, axis2;
00079 
00080                 if (flag & IK_XDOF) {
00081                         axis1 = 0;
00082                         axis2 = (flag & IK_YDOF)? 1: 2;
00083                 }
00084                 else {
00085                         axis1 = 1;
00086                         axis2 = 2;
00087                 }
00088 
00089                 if (translate)
00090                         seg = new IK_QTranslateSegment(axis1, axis2);
00091                 else {
00092                         if (axis1 + axis2 == 2)
00093                                 seg = new IK_QSwingSegment();
00094                         else
00095                                 seg = new IK_QElbowSegment((axis1 == 0)? 0: 2);
00096                 }
00097         }
00098         else {
00099                 if (translate)
00100                         seg = new IK_QTranslateSegment();
00101                 else
00102                         seg = new IK_QSphericalSegment();
00103         }
00104 
00105         return seg;
00106 }
00107 
00108 IK_Segment *IK_CreateSegment(int flag)
00109 {
00110         IK_QSegment *rot = CreateSegment(flag, false);
00111         IK_QSegment *trans = CreateSegment(flag >> 3, true);
00112 
00113         IK_QSegment *seg;
00114 
00115         if (rot == NULL && trans == NULL)
00116                 seg = new IK_QNullSegment();
00117         else if (rot == NULL)
00118                 seg = trans;
00119         else {
00120                 seg = rot;
00121 
00122                 // make it seem from the interface as if the rotation and translation
00123                 // segment are one
00124                 if (trans) {
00125                         seg->SetComposite(trans);
00126                         trans->SetParent(seg);
00127                 }
00128         }
00129 
00130         return seg;
00131 }
00132 
00133 void IK_FreeSegment(IK_Segment *seg)
00134 {
00135         IK_QSegment *qseg = (IK_QSegment*)seg;
00136 
00137         if (qseg->Composite())
00138                 delete qseg->Composite();
00139         delete qseg;
00140 }
00141 
00142 void IK_SetParent(IK_Segment *seg, IK_Segment *parent)
00143 {
00144         IK_QSegment *qseg = (IK_QSegment*)seg;
00145         IK_QSegment *qparent = (IK_QSegment*)parent;
00146 
00147         if (qparent && qparent->Composite())
00148                 qseg->SetParent(qparent->Composite());
00149         else
00150                 qseg->SetParent(qparent);
00151 }
00152 
00153 void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float basis[][3], float length)
00154 {
00155         IK_QSegment *qseg = (IK_QSegment*)seg;
00156 
00157         MT_Vector3 mstart(start);
00158         // convert from blender column major to moto row major
00159         MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0],
00160                             basis[0][1], basis[1][1], basis[2][1],
00161                             basis[0][2], basis[1][2], basis[2][2]);
00162         MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0],
00163                            rest[0][1], rest[1][1], rest[2][1],
00164                            rest[0][2], rest[1][2], rest[2][2]);
00165         MT_Scalar mlength(length);
00166 
00167         if (qseg->Composite()) {
00168                 MT_Vector3 cstart(0, 0, 0);
00169                 MT_Matrix3x3 cbasis;
00170                 cbasis.setIdentity();
00171                 
00172                 qseg->SetTransform(mstart, mrest, mbasis, 0.0);
00173                 qseg->Composite()->SetTransform(cstart, cbasis, cbasis, mlength);
00174         }
00175         else
00176                 qseg->SetTransform(mstart, mrest, mbasis, mlength);
00177 }
00178 
00179 void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax)
00180 {
00181         IK_QSegment *qseg = (IK_QSegment*)seg;
00182 
00183         if (axis >= IK_TRANS_X) {
00184                 if(!qseg->Translational()) {
00185                         if(qseg->Composite() && qseg->Composite()->Translational())
00186                                 qseg = qseg->Composite();
00187                         else
00188                                 return;
00189                 }
00190 
00191                 if(axis == IK_TRANS_X) axis = IK_X;
00192                 else if(axis == IK_TRANS_Y) axis = IK_Y;
00193                 else axis = IK_Z;
00194         }
00195 
00196         qseg->SetLimit(axis, lmin, lmax);
00197 }
00198 
00199 void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness)
00200 {
00201         if (stiffness < 0.0)
00202                 return;
00203         
00204         if (stiffness > 0.999)
00205                 stiffness = 0.999;
00206 
00207         IK_QSegment *qseg = (IK_QSegment*)seg;
00208         MT_Scalar weight = 1.0-stiffness;
00209 
00210         if (axis >= IK_TRANS_X) {
00211                 if(!qseg->Translational()) {
00212                         if(qseg->Composite() && qseg->Composite()->Translational())
00213                                 qseg = qseg->Composite();
00214                         else
00215                                 return;
00216                 }
00217 
00218                 if(axis == IK_TRANS_X) axis = IK_X;
00219                 else if(axis == IK_TRANS_Y) axis = IK_Y;
00220                 else axis = IK_Z;
00221         }
00222 
00223         qseg->SetWeight(axis, weight);
00224 }
00225 
00226 void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
00227 {
00228         IK_QSegment *qseg = (IK_QSegment*)seg;
00229         const MT_Matrix3x3& change = qseg->BasisChange();
00230 
00231         if (qseg->Translational() && qseg->Composite())
00232                 qseg = qseg->Composite();
00233 
00234         // convert from moto row major to blender column major
00235         basis_change[0][0] = (float)change[0][0];
00236         basis_change[1][0] = (float)change[0][1];
00237         basis_change[2][0] = (float)change[0][2];
00238         basis_change[0][1] = (float)change[1][0];
00239         basis_change[1][1] = (float)change[1][1];
00240         basis_change[2][1] = (float)change[1][2];
00241         basis_change[0][2] = (float)change[2][0];
00242         basis_change[1][2] = (float)change[2][1];
00243         basis_change[2][2] = (float)change[2][2];
00244 }
00245 
00246 void IK_GetTranslationChange(IK_Segment *seg, float *translation_change)
00247 {
00248         IK_QSegment *qseg = (IK_QSegment*)seg;
00249 
00250         if (!qseg->Translational() && qseg->Composite())
00251                 qseg = qseg->Composite();
00252         
00253         const MT_Vector3& change = qseg->TranslationChange();
00254 
00255         translation_change[0] = (float)change[0];
00256         translation_change[1] = (float)change[1];
00257         translation_change[2] = (float)change[2];
00258 }
00259 
00260 IK_Solver *IK_CreateSolver(IK_Segment *root)
00261 {
00262         if (root == NULL)
00263                 return NULL;
00264         
00265         IK_QSolver *solver = new IK_QSolver();
00266         solver->root = (IK_QSegment*)root;
00267 
00268         return (IK_Solver*)solver;
00269 }
00270 
00271 void IK_FreeSolver(IK_Solver *solver)
00272 {
00273         if (solver == NULL)
00274                 return;
00275 
00276         IK_QSolver *qsolver = (IK_QSolver*)solver;
00277         std::list<IK_QTask*>& tasks = qsolver->tasks;
00278         std::list<IK_QTask*>::iterator task;
00279 
00280         for (task = tasks.begin(); task != tasks.end(); task++)
00281                 delete (*task);
00282         
00283         delete qsolver;
00284 }
00285 
00286 void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight)
00287 {
00288         if (solver == NULL || tip == NULL)
00289                 return;
00290 
00291         IK_QSolver *qsolver = (IK_QSolver*)solver;
00292         IK_QSegment *qtip = (IK_QSegment*)tip;
00293 
00294         if (qtip->Composite())
00295                 qtip = qtip->Composite();
00296 
00297         MT_Vector3 pos(goal);
00298 
00299         IK_QTask *ee = new IK_QPositionTask(true, qtip, pos);
00300         ee->SetWeight(weight);
00301         qsolver->tasks.push_back(ee);
00302 }
00303 
00304 void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight)
00305 {
00306         if (solver == NULL || tip == NULL)
00307                 return;
00308 
00309         IK_QSolver *qsolver = (IK_QSolver*)solver;
00310         IK_QSegment *qtip = (IK_QSegment*)tip;
00311 
00312         if (qtip->Composite())
00313                 qtip = qtip->Composite();
00314 
00315         // convert from blender column major to moto row major
00316         MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0],
00317                          goal[0][1], goal[1][1], goal[2][1],
00318                          goal[0][2], goal[1][2], goal[2][2]);
00319 
00320         IK_QTask *orient = new IK_QOrientationTask(true, qtip, rot);
00321         orient->SetWeight(weight);
00322         qsolver->tasks.push_back(orient);
00323 }
00324 
00325 void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle)
00326 {
00327         if (solver == NULL || tip == NULL)
00328                 return;
00329 
00330         IK_QSolver *qsolver = (IK_QSolver*)solver;
00331         IK_QSegment *qtip = (IK_QSegment*)tip;
00332 
00333         MT_Vector3 qgoal(goal);
00334         MT_Vector3 qpolegoal(polegoal);
00335 
00336         qsolver->solver.SetPoleVectorConstraint(
00337                 qtip, qgoal, qpolegoal, poleangle, getangle);
00338 }
00339 
00340 float IK_SolverGetPoleAngle(IK_Solver *solver)
00341 {
00342         if (solver == NULL)
00343                 return 0.0f;
00344 
00345         IK_QSolver *qsolver = (IK_QSolver*)solver;
00346 
00347         return qsolver->solver.GetPoleAngle();
00348 }
00349 
00350 void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight)
00351 {
00352         if (solver == NULL || root == NULL)
00353                 return;
00354 
00355         IK_QSolver *qsolver = (IK_QSolver*)solver;
00356         IK_QSegment *qroot = (IK_QSegment*)root;
00357 
00358         // convert from blender column major to moto row major
00359         MT_Vector3 center(goal);
00360 
00361         IK_QTask *com = new IK_QCenterOfMassTask(true, qroot, center);
00362         com->SetWeight(weight);
00363         qsolver->tasks.push_back(com);
00364 }
00365 
00366 int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations)
00367 {
00368         if (solver == NULL)
00369                 return 0;
00370 
00371         IK_QSolver *qsolver = (IK_QSolver*)solver;
00372 
00373         IK_QSegment *root = qsolver->root;
00374         IK_QJacobianSolver& jacobian = qsolver->solver;
00375         std::list<IK_QTask*>& tasks = qsolver->tasks;
00376         MT_Scalar tol = tolerance;
00377 
00378         if(!jacobian.Setup(root, tasks))
00379                 return 0;
00380 
00381         bool result = jacobian.Solve(root, tasks, tol, max_iterations);
00382 
00383         return ((result)? 1: 0);
00384 }
00385