Blender V2.61 - r43446

IK_Solver.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Original Author: Laurence
00024  * Contributor(s): Brecht
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include "../extern/IK_solver.h"
00035 
00036 #include "IK_QJacobianSolver.h"
00037 #include "IK_QSegment.h"
00038 #include "IK_QTask.h"
00039 
00040 #include <list>
00041 using namespace std;
00042 
00043 class IK_QSolver {
00044 public:
00045     IK_QSolver() : root(NULL) {};
00046 
00047     IK_QJacobianSolver solver;
00048     IK_QSegment *root;
00049     std::list<IK_QTask*> tasks;
00050 };
00051 
00052 // FIXME: locks still result in small "residual" changes to the locked axes...
00053 IK_QSegment *CreateSegment(int flag, bool translate)
00054 {
00055     int ndof = 0;
00056     ndof += (flag & IK_XDOF)? 1: 0;
00057     ndof += (flag & IK_YDOF)? 1: 0;
00058     ndof += (flag & IK_ZDOF)? 1: 0;
00059 
00060     IK_QSegment *seg;
00061 
00062     if (ndof == 0)
00063         return NULL;
00064     else if (ndof == 1) {
00065         int axis;
00066 
00067         if (flag & IK_XDOF) axis = 0;
00068         else if (flag & IK_YDOF) axis = 1;
00069         else axis = 2;
00070 
00071         if (translate)
00072             seg = new IK_QTranslateSegment(axis);
00073         else
00074             seg = new IK_QRevoluteSegment(axis);
00075     }
00076     else if (ndof == 2) {
00077         int axis1, axis2;
00078 
00079         if (flag & IK_XDOF) {
00080             axis1 = 0;
00081             axis2 = (flag & IK_YDOF)? 1: 2;
00082         }
00083         else {
00084             axis1 = 1;
00085             axis2 = 2;
00086         }
00087 
00088         if (translate)
00089             seg = new IK_QTranslateSegment(axis1, axis2);
00090         else {
00091             if (axis1 + axis2 == 2)
00092                 seg = new IK_QSwingSegment();
00093             else
00094                 seg = new IK_QElbowSegment((axis1 == 0)? 0: 2);
00095         }
00096     }
00097     else {
00098         if (translate)
00099             seg = new IK_QTranslateSegment();
00100         else
00101             seg = new IK_QSphericalSegment();
00102     }
00103 
00104     return seg;
00105 }
00106 
00107 IK_Segment *IK_CreateSegment(int flag)
00108 {
00109     IK_QSegment *rot = CreateSegment(flag, false);
00110     IK_QSegment *trans = CreateSegment(flag >> 3, true);
00111 
00112     IK_QSegment *seg;
00113 
00114     if (rot == NULL && trans == NULL)
00115         seg = new IK_QNullSegment();
00116     else if (rot == NULL)
00117         seg = trans;
00118     else {
00119         seg = rot;
00120 
00121         // make it seem from the interface as if the rotation and translation
00122         // segment are one
00123         if (trans) {
00124             seg->SetComposite(trans);
00125             trans->SetParent(seg);
00126         }
00127     }
00128 
00129     return seg;
00130 }
00131 
00132 void IK_FreeSegment(IK_Segment *seg)
00133 {
00134     IK_QSegment *qseg = (IK_QSegment*)seg;
00135 
00136     if (qseg->Composite())
00137         delete qseg->Composite();
00138     delete qseg;
00139 }
00140 
00141 void IK_SetParent(IK_Segment *seg, IK_Segment *parent)
00142 {
00143     IK_QSegment *qseg = (IK_QSegment*)seg;
00144     IK_QSegment *qparent = (IK_QSegment*)parent;
00145 
00146     if (qparent && qparent->Composite())
00147         qseg->SetParent(qparent->Composite());
00148     else
00149         qseg->SetParent(qparent);
00150 }
00151 
00152 void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float basis[][3], float length)
00153 {
00154     IK_QSegment *qseg = (IK_QSegment*)seg;
00155 
00156     MT_Vector3 mstart(start);
00157     // convert from blender column major to moto row major
00158     MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0],
00159                         basis[0][1], basis[1][1], basis[2][1],
00160                         basis[0][2], basis[1][2], basis[2][2]);
00161     MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0],
00162                        rest[0][1], rest[1][1], rest[2][1],
00163                        rest[0][2], rest[1][2], rest[2][2]);
00164     MT_Scalar mlength(length);
00165 
00166     if (qseg->Composite()) {
00167         MT_Vector3 cstart(0, 0, 0);
00168         MT_Matrix3x3 cbasis;
00169         cbasis.setIdentity();
00170         
00171         qseg->SetTransform(mstart, mrest, mbasis, 0.0);
00172         qseg->Composite()->SetTransform(cstart, cbasis, cbasis, mlength);
00173     }
00174     else
00175         qseg->SetTransform(mstart, mrest, mbasis, mlength);
00176 }
00177 
00178 void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax)
00179 {
00180     IK_QSegment *qseg = (IK_QSegment*)seg;
00181 
00182     if (axis >= IK_TRANS_X) {
00183         if(!qseg->Translational()) {
00184             if(qseg->Composite() && qseg->Composite()->Translational())
00185                 qseg = qseg->Composite();
00186             else
00187                 return;
00188         }
00189 
00190         if(axis == IK_TRANS_X) axis = IK_X;
00191         else if(axis == IK_TRANS_Y) axis = IK_Y;
00192         else axis = IK_Z;
00193     }
00194 
00195     qseg->SetLimit(axis, lmin, lmax);
00196 }
00197 
00198 void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness)
00199 {
00200     if (stiffness < 0.0)
00201         return;
00202     
00203     if (stiffness > 0.999)
00204         stiffness = 0.999;
00205 
00206     IK_QSegment *qseg = (IK_QSegment*)seg;
00207     MT_Scalar weight = 1.0-stiffness;
00208 
00209     if (axis >= IK_TRANS_X) {
00210         if(!qseg->Translational()) {
00211             if(qseg->Composite() && qseg->Composite()->Translational())
00212                 qseg = qseg->Composite();
00213             else
00214                 return;
00215         }
00216 
00217         if(axis == IK_TRANS_X) axis = IK_X;
00218         else if(axis == IK_TRANS_Y) axis = IK_Y;
00219         else axis = IK_Z;
00220     }
00221 
00222     qseg->SetWeight(axis, weight);
00223 }
00224 
00225 void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
00226 {
00227     IK_QSegment *qseg = (IK_QSegment*)seg;
00228 
00229     if (qseg->Translational() && qseg->Composite())
00230         qseg = qseg->Composite();
00231 
00232     const MT_Matrix3x3& change = qseg->BasisChange();
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