Blender V2.61 - r43446

IK_QSegment.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 "IK_QSegment.h"
00035 #include <cmath>
00036 
00037 // Utility functions
00038 
00039 static MT_Matrix3x3 RotationMatrix(MT_Scalar sine, MT_Scalar cosine, int axis)
00040 {
00041     if (axis == 0)
00042         return MT_Matrix3x3(1.0, 0.0, 0.0,
00043                             0.0, cosine, -sine,
00044                             0.0, sine, cosine);
00045     else if (axis == 1)
00046         return MT_Matrix3x3(cosine, 0.0, sine,
00047                             0.0, 1.0, 0.0,
00048                             -sine, 0.0, cosine);
00049     else
00050         return MT_Matrix3x3(cosine, -sine, 0.0,
00051                             sine, cosine, 0.0,
00052                             0.0, 0.0, 1.0);
00053 }
00054 
00055 static MT_Matrix3x3 RotationMatrix(MT_Scalar angle, int axis)
00056 {
00057     return RotationMatrix(sin(angle), cos(angle), axis);
00058 }
00059 
00060 
00061 static MT_Scalar EulerAngleFromMatrix(const MT_Matrix3x3& R, int axis)
00062 {
00063     MT_Scalar t = sqrt(R[0][0]*R[0][0] + R[0][1]*R[0][1]);
00064 
00065     if (t > 16.0*MT_EPSILON) {
00066         if (axis == 0) return -atan2(R[1][2], R[2][2]);
00067         else if(axis == 1) return atan2(-R[0][2], t);
00068         else return -atan2(R[0][1], R[0][0]);
00069     } else {
00070         if (axis == 0) return -atan2(-R[2][1], R[1][1]);
00071         else if(axis == 1) return atan2(-R[0][2], t);
00072         else return 0.0f;
00073     }
00074 }
00075 
00076 static MT_Scalar safe_acos(MT_Scalar f)
00077 {
00078     if (f <= -1.0f)
00079         return MT_PI;
00080     else if (f >= 1.0f)
00081         return 0.0;
00082     else
00083         return acos(f);
00084 }
00085 
00086 static MT_Scalar ComputeTwist(const MT_Matrix3x3& R)
00087 {
00088     // qy and qw are the y and w components of the quaternion from R
00089     MT_Scalar qy = R[0][2] - R[2][0];
00090     MT_Scalar qw = R[0][0] + R[1][1] + R[2][2] + 1;
00091 
00092     MT_Scalar tau = 2*atan2(qy, qw);
00093 
00094     return tau;
00095 }
00096 
00097 static MT_Matrix3x3 ComputeTwistMatrix(MT_Scalar tau)
00098 {
00099     return RotationMatrix(tau, 1);
00100 }
00101 
00102 static void RemoveTwist(MT_Matrix3x3& R)
00103 {
00104     // compute twist parameter
00105     MT_Scalar tau = ComputeTwist(R);
00106 
00107     // compute twist matrix
00108     MT_Matrix3x3 T = ComputeTwistMatrix(tau);
00109 
00110     // remove twist
00111     R = R*T.transposed();
00112 }
00113 
00114 static MT_Vector3 SphericalRangeParameters(const MT_Matrix3x3& R)
00115 {
00116     // compute twist parameter
00117     MT_Scalar tau = ComputeTwist(R);
00118 
00119     // compute swing parameters
00120     MT_Scalar num = 2.0*(1.0 + R[1][1]);
00121 
00122     // singularity at pi
00123     if (MT_abs(num) < MT_EPSILON)
00124         // TODO: this does now rotation of size pi over z axis, but could
00125         // be any axis, how to deal with this i'm not sure, maybe don't
00126         // enforce limits at all then
00127         return MT_Vector3(0.0, tau, 1.0);
00128 
00129     num = 1.0/sqrt(num);
00130     MT_Scalar ax = -R[2][1]*num;
00131     MT_Scalar az = R[0][1]*num;
00132 
00133     return MT_Vector3(ax, tau, az);
00134 }
00135 
00136 static MT_Matrix3x3 ComputeSwingMatrix(MT_Scalar ax, MT_Scalar az)
00137 {
00138     // length of (ax, 0, az) = sin(theta/2)
00139     MT_Scalar sine2 = ax*ax + az*az;
00140     MT_Scalar cosine2 = sqrt((sine2 >= 1.0)? 0.0: 1.0-sine2);
00141 
00142     // compute swing matrix
00143     MT_Matrix3x3 S(MT_Quaternion(ax, 0.0, az, -cosine2));
00144 
00145     return S;
00146 }
00147 
00148 static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R)
00149 {
00150     MT_Vector3 delta = MT_Vector3(R[2][1] - R[1][2],
00151                                   R[0][2] - R[2][0],
00152                                   R[1][0] - R[0][1]);
00153 
00154     MT_Scalar c = safe_acos((R[0][0] + R[1][1] + R[2][2] - 1)/2);
00155     MT_Scalar l = delta.length();
00156     
00157     if (!MT_fuzzyZero(l))
00158         delta *= c/l;
00159     
00160     return delta;
00161 }
00162 
00163 static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax)
00164 {
00165     MT_Scalar xlim, zlim, x, z;
00166 
00167     if (ax < 0.0) {
00168         x = -ax;
00169         xlim = -amin[0];
00170     }
00171     else {
00172         x = ax;
00173         xlim = amax[0];
00174     }
00175 
00176     if (az < 0.0) {
00177         z = -az;
00178         zlim = -amin[1];
00179     }
00180     else {
00181         z = az;
00182         zlim = amax[1];
00183     }
00184 
00185     if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) {
00186         if (x <= xlim && z <= zlim)
00187             return false;
00188 
00189         if (x > xlim)
00190             x = xlim;
00191         if (z > zlim)
00192             z = zlim;
00193     }
00194     else {
00195         MT_Scalar invx = 1.0/(xlim*xlim);
00196         MT_Scalar invz = 1.0/(zlim*zlim);
00197 
00198         if ((x*x*invx + z*z*invz) <= 1.0)
00199             return false;
00200 
00201         if (MT_fuzzyZero(x)) {
00202             x = 0.0;
00203             z = zlim;
00204         }
00205         else {
00206             MT_Scalar rico = z/x;
00207             MT_Scalar old_x = x;
00208             x = sqrt(1.0/(invx + invz*rico*rico));
00209             if (old_x < 0.0)
00210                 x = -x;
00211             z = rico*x;
00212         }
00213     }
00214 
00215     ax = (ax < 0.0)? -x: x;
00216     az = (az < 0.0)? -z: z;
00217 
00218     return true;
00219 }
00220 
00221 // IK_QSegment
00222 
00223 IK_QSegment::IK_QSegment(int num_DoF, bool translational)
00224 : m_parent(NULL), m_child(NULL), m_sibling(NULL), m_composite(NULL),
00225   m_num_DoF(num_DoF), m_translational(translational)
00226 {
00227     m_locked[0] = m_locked[1] = m_locked[2] = false;
00228     m_weight[0] = m_weight[1] = m_weight[2] = 1.0;
00229 
00230     m_max_extension = 0.0;
00231 
00232     m_start = MT_Vector3(0, 0, 0);
00233     m_rest_basis.setIdentity();
00234     m_basis.setIdentity();
00235     m_translation = MT_Vector3(0, 0, 0);
00236 
00237     m_orig_basis = m_basis;
00238     m_orig_translation = m_translation;
00239 }
00240 
00241 void IK_QSegment::Reset()
00242 {
00243     m_locked[0] = m_locked[1] = m_locked[2] = false;
00244 
00245     m_basis = m_orig_basis;
00246     m_translation = m_orig_translation;
00247     SetBasis(m_basis);
00248 
00249     for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling)
00250         seg->Reset();
00251 }
00252 
00253 void IK_QSegment::SetTransform(
00254     const MT_Vector3& start,
00255     const MT_Matrix3x3& rest_basis,
00256     const MT_Matrix3x3& basis,
00257     const MT_Scalar length
00258 )
00259 {
00260     m_max_extension = start.length() + length;  
00261 
00262     m_start = start;
00263     m_rest_basis = rest_basis;
00264 
00265     m_orig_basis = basis;
00266     SetBasis(basis);
00267 
00268     m_translation = MT_Vector3(0, length, 0);
00269     m_orig_translation = m_translation;
00270 }
00271 
00272 MT_Matrix3x3 IK_QSegment::BasisChange() const
00273 {
00274     return m_orig_basis.transposed()*m_basis;
00275 }
00276 
00277 MT_Vector3 IK_QSegment::TranslationChange() const
00278 {
00279     return m_translation - m_orig_translation;
00280 }
00281 
00282 IK_QSegment::~IK_QSegment()
00283 {
00284     if (m_parent)
00285         m_parent->RemoveChild(this);
00286 
00287     for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling)
00288         seg->m_parent = NULL;
00289 }
00290 
00291 void IK_QSegment::SetParent(IK_QSegment *parent)
00292 {
00293     if (m_parent == parent)
00294         return;
00295     
00296     if (m_parent)
00297         m_parent->RemoveChild(this);
00298     
00299     if (parent) {
00300         m_sibling = parent->m_child;
00301         parent->m_child = this;
00302     }
00303 
00304     m_parent = parent;
00305 }
00306 
00307 void IK_QSegment::SetComposite(IK_QSegment *seg)
00308 {
00309     m_composite = seg;
00310 }
00311 
00312 void IK_QSegment::RemoveChild(IK_QSegment *child)
00313 {
00314     if (m_child == NULL)
00315         return;
00316     else if (m_child == child)
00317         m_child = m_child->m_sibling;
00318     else {
00319         IK_QSegment *seg = m_child;
00320 
00321         while (seg->m_sibling != child)
00322             seg = seg->m_sibling;
00323 
00324         if (child == seg->m_sibling)
00325             seg->m_sibling = child->m_sibling;
00326     }
00327 }
00328 
00329 void IK_QSegment::UpdateTransform(const MT_Transform& global)
00330 {
00331     // compute the global transform at the end of the segment
00332     m_global_start = global.getOrigin() + global.getBasis()*m_start;
00333 
00334     m_global_transform.setOrigin(m_global_start);
00335     m_global_transform.setBasis(global.getBasis() * m_rest_basis * m_basis);
00336     m_global_transform.translate(m_translation);
00337 
00338     // update child transforms
00339     for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling)
00340         seg->UpdateTransform(m_global_transform);
00341 }
00342 
00343 void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat)
00344 {
00345     m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis;
00346 }
00347 
00348 void IK_QSegment::Scale(float scale)
00349 {
00350     m_start *= scale;
00351     m_translation *= scale;
00352     m_orig_translation *= scale;
00353     m_global_start *= scale;
00354     m_global_transform.getOrigin() *= scale;
00355     m_max_extension *= scale;
00356 }
00357 
00358 // IK_QSphericalSegment
00359 
00360 IK_QSphericalSegment::IK_QSphericalSegment()
00361 : IK_QSegment(3, false), m_limit_x(false), m_limit_y(false), m_limit_z(false)
00362 {
00363 }
00364 
00365 MT_Vector3 IK_QSphericalSegment::Axis(int dof) const
00366 {
00367     return m_global_transform.getBasis().getColumn(dof);
00368 }
00369 
00370 void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
00371 {
00372     if (lmin > lmax)
00373         return;
00374     
00375     if (axis == 1) {
00376         lmin = MT_clamp(lmin, -MT_PI, MT_PI);
00377         lmax = MT_clamp(lmax, -MT_PI, MT_PI);
00378 
00379         m_min_y = lmin;
00380         m_max_y = lmax;
00381 
00382         m_limit_y = true;
00383     }
00384     else {
00385         // clamp and convert to axis angle parameters
00386         lmin = MT_clamp(lmin, -MT_PI, MT_PI);
00387         lmax = MT_clamp(lmax, -MT_PI, MT_PI);
00388 
00389         lmin = sin(lmin*0.5);
00390         lmax = sin(lmax*0.5);
00391 
00392         if (axis == 0) {
00393             m_min[0] = -lmax;
00394             m_max[0] = -lmin;
00395             m_limit_x = true;
00396         }
00397         else if (axis == 2) {
00398             m_min[1] = -lmax;
00399             m_max[1] = -lmin;
00400             m_limit_z = true;
00401         }
00402     }
00403 }
00404 
00405 void IK_QSphericalSegment::SetWeight(int axis, MT_Scalar weight)
00406 {
00407     m_weight[axis] = weight;
00408 }
00409 
00410 bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
00411 {
00412     if (m_locked[0] && m_locked[1] && m_locked[2])
00413         return false;
00414 
00415     MT_Vector3 dq;
00416     dq.x() = jacobian.AngleUpdate(m_DoF_id);
00417     dq.y() = jacobian.AngleUpdate(m_DoF_id+1);
00418     dq.z() = jacobian.AngleUpdate(m_DoF_id+2);
00419 
00420     // Directly update the rotation matrix, with Rodrigues' rotation formula,
00421     // to avoid singularities and allow smooth integration.
00422 
00423     MT_Scalar theta = dq.length();
00424 
00425     if (!MT_fuzzyZero(theta)) {
00426         MT_Vector3 w = dq*(1.0/theta);
00427 
00428         MT_Scalar sine = sin(theta);
00429         MT_Scalar cosine = cos(theta);
00430         MT_Scalar cosineInv = 1-cosine;
00431 
00432         MT_Scalar xsine = w.x()*sine;
00433         MT_Scalar ysine = w.y()*sine;
00434         MT_Scalar zsine = w.z()*sine;
00435 
00436         MT_Scalar xxcosine = w.x()*w.x()*cosineInv;
00437         MT_Scalar xycosine = w.x()*w.y()*cosineInv;
00438         MT_Scalar xzcosine = w.x()*w.z()*cosineInv;
00439         MT_Scalar yycosine = w.y()*w.y()*cosineInv;
00440         MT_Scalar yzcosine = w.y()*w.z()*cosineInv;
00441         MT_Scalar zzcosine = w.z()*w.z()*cosineInv;
00442 
00443         MT_Matrix3x3 M(
00444             cosine + xxcosine, -zsine + xycosine, ysine + xzcosine,
00445             zsine + xycosine, cosine + yycosine, -xsine + yzcosine,
00446             -ysine + xzcosine, xsine + yzcosine, cosine + zzcosine);
00447 
00448         m_new_basis = m_basis*M;
00449     }
00450     else
00451         m_new_basis = m_basis;
00452 
00453     
00454     if (m_limit_y == false && m_limit_x == false && m_limit_z == false)
00455         return false;
00456 
00457     MT_Vector3 a = SphericalRangeParameters(m_new_basis);
00458 
00459     if (m_locked[0])
00460         a.x() = m_locked_ax;
00461     if (m_locked[1])
00462         a.y() = m_locked_ay;
00463     if (m_locked[2])
00464         a.z() = m_locked_az;
00465 
00466     MT_Scalar ax = a.x(), ay = a.y(), az = a.z();
00467 
00468     clamp[0] = clamp[1] = clamp[2] =  false;
00469     
00470     if (m_limit_y) {
00471         if (a.y() > m_max_y) {
00472             ay = m_max_y;
00473             clamp[1] = true;
00474         }
00475         else if (a.y() < m_min_y) {
00476             ay = m_min_y;
00477             clamp[1] = true;
00478         }
00479     }
00480 
00481     if (m_limit_x && m_limit_z) {
00482         if (EllipseClamp(ax, az, m_min, m_max))
00483             clamp[0] = clamp[2] = true;
00484     }
00485     else if (m_limit_x) {
00486         if (ax < m_min[0]) {
00487             ax = m_min[0];
00488             clamp[0] = true;
00489         }
00490         else if (ax > m_max[0]) {
00491             ax = m_max[0];
00492             clamp[0] = true;
00493         }
00494     }
00495     else if (m_limit_z) {
00496         if (az < m_min[1]) {
00497             az = m_min[1];
00498             clamp[2] = true;
00499         }
00500         else if (az > m_max[1]) {
00501             az = m_max[1];
00502             clamp[2] = true;
00503         }
00504     }
00505 
00506     if (clamp[0] == false && clamp[1] == false && clamp[2] == false) {
00507         if (m_locked[0] || m_locked[1] || m_locked[2])
00508             m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay);
00509         return false;
00510     }
00511     
00512     m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay);
00513 
00514     delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis);
00515 
00516     if (!(m_locked[0] || m_locked[2]) && (clamp[0] || clamp[2])) {
00517         m_locked_ax = ax;
00518         m_locked_az = az;
00519     }
00520 
00521     if (!m_locked[1] && clamp[1])
00522         m_locked_ay = ay;
00523     
00524     return true;
00525 }
00526 
00527 void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
00528 {
00529     if (dof == 1) {
00530         m_locked[1] = true;
00531         jacobian.Lock(m_DoF_id+1, delta[1]);
00532     }
00533     else {
00534         m_locked[0] = m_locked[2] = true;
00535         jacobian.Lock(m_DoF_id, delta[0]);
00536         jacobian.Lock(m_DoF_id+2, delta[2]);
00537     }
00538 }
00539 
00540 void IK_QSphericalSegment::UpdateAngleApply()
00541 {
00542     m_basis = m_new_basis;
00543 }
00544 
00545 // IK_QNullSegment
00546 
00547 IK_QNullSegment::IK_QNullSegment()
00548 : IK_QSegment(0, false)
00549 {
00550 }
00551 
00552 // IK_QRevoluteSegment
00553 
00554 IK_QRevoluteSegment::IK_QRevoluteSegment(int axis)
00555 : IK_QSegment(1, false), m_axis(axis), m_angle(0.0), m_limit(false)
00556 {
00557 }
00558 
00559 void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis)
00560 {
00561     if (m_axis == 1) {
00562         m_angle = ComputeTwist(basis);
00563         m_basis = ComputeTwistMatrix(m_angle);
00564     }
00565     else {
00566         m_angle = EulerAngleFromMatrix(basis, m_axis);
00567         m_basis = RotationMatrix(m_angle, m_axis);
00568     }
00569 }
00570 
00571 MT_Vector3 IK_QRevoluteSegment::Axis(int) const
00572 {
00573     return m_global_transform.getBasis().getColumn(m_axis);
00574 }
00575 
00576 bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
00577 {
00578     if (m_locked[0])
00579         return false;
00580 
00581     m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id);
00582 
00583     clamp[0] = false;
00584 
00585     if (m_limit == false)
00586         return false;
00587 
00588     if (m_new_angle > m_max)
00589         delta[0] = m_max - m_angle;
00590     else if (m_new_angle < m_min)
00591         delta[0] = m_min - m_angle;
00592     else
00593         return false;
00594     
00595     clamp[0] = true;
00596     m_new_angle = m_angle + delta[0];
00597 
00598     return true;
00599 }
00600 
00601 void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta)
00602 {
00603     m_locked[0] = true;
00604     jacobian.Lock(m_DoF_id, delta[0]);
00605 }
00606 
00607 void IK_QRevoluteSegment::UpdateAngleApply()
00608 {
00609     m_angle = m_new_angle;
00610     m_basis = RotationMatrix(m_angle, m_axis);
00611 }
00612 
00613 void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
00614 {
00615     if (lmin > lmax || m_axis != axis)
00616         return;
00617     
00618     // clamp and convert to axis angle parameters
00619     lmin = MT_clamp(lmin, -MT_PI, MT_PI);
00620     lmax = MT_clamp(lmax, -MT_PI, MT_PI);
00621 
00622     m_min = lmin;
00623     m_max = lmax;
00624 
00625     m_limit = true;
00626 }
00627 
00628 void IK_QRevoluteSegment::SetWeight(int axis, MT_Scalar weight)
00629 {
00630     if (axis == m_axis)
00631         m_weight[0] = weight;
00632 }
00633 
00634 // IK_QSwingSegment
00635 
00636 IK_QSwingSegment::IK_QSwingSegment()
00637 : IK_QSegment(2, false), m_limit_x(false), m_limit_z(false)
00638 {
00639 }
00640 
00641 void IK_QSwingSegment::SetBasis(const MT_Matrix3x3& basis)
00642 {
00643     m_basis = basis;
00644     RemoveTwist(m_basis);
00645 }
00646 
00647 MT_Vector3 IK_QSwingSegment::Axis(int dof) const
00648 {
00649     return m_global_transform.getBasis().getColumn((dof==0)? 0: 2);
00650 }
00651 
00652 bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
00653 {
00654     if (m_locked[0] && m_locked[1])
00655         return false;
00656 
00657     MT_Vector3 dq;
00658     dq.x() = jacobian.AngleUpdate(m_DoF_id);
00659     dq.y() = 0.0;
00660     dq.z() = jacobian.AngleUpdate(m_DoF_id+1);
00661 
00662     // Directly update the rotation matrix, with Rodrigues' rotation formula,
00663     // to avoid singularities and allow smooth integration.
00664 
00665     MT_Scalar theta = dq.length();
00666 
00667     if (!MT_fuzzyZero(theta)) {
00668         MT_Vector3 w = dq*(1.0/theta);
00669 
00670         MT_Scalar sine = sin(theta);
00671         MT_Scalar cosine = cos(theta);
00672         MT_Scalar cosineInv = 1-cosine;
00673 
00674         MT_Scalar xsine = w.x()*sine;
00675         MT_Scalar zsine = w.z()*sine;
00676 
00677         MT_Scalar xxcosine = w.x()*w.x()*cosineInv;
00678         MT_Scalar xzcosine = w.x()*w.z()*cosineInv;
00679         MT_Scalar zzcosine = w.z()*w.z()*cosineInv;
00680 
00681         MT_Matrix3x3 M(
00682             cosine + xxcosine, -zsine, xzcosine,
00683             zsine, cosine, -xsine,
00684             xzcosine, xsine, cosine + zzcosine);
00685 
00686         m_new_basis = m_basis*M;
00687 
00688         RemoveTwist(m_new_basis);
00689     }
00690     else
00691         m_new_basis = m_basis;
00692 
00693     if (m_limit_x == false && m_limit_z == false)
00694         return false;
00695 
00696     MT_Vector3 a = SphericalRangeParameters(m_new_basis);
00697     MT_Scalar ax = 0, az = 0;
00698 
00699     clamp[0] = clamp[1] = false;
00700     
00701     if (m_limit_x && m_limit_z) {
00702         ax = a.x();
00703         az = a.z();
00704 
00705         if (EllipseClamp(ax, az, m_min, m_max))
00706             clamp[0] = clamp[1] = true;
00707     }
00708     else if (m_limit_x) {
00709         if (ax < m_min[0]) {
00710             ax = m_min[0];
00711             clamp[0] = true;
00712         }
00713         else if (ax > m_max[0]) {
00714             ax = m_max[0];
00715             clamp[0] = true;
00716         }
00717     }
00718     else if (m_limit_z) {
00719         if (az < m_min[1]) {
00720             az = m_min[1];
00721             clamp[1] = true;
00722         }
00723         else if (az > m_max[1]) {
00724             az = m_max[1];
00725             clamp[1] = true;
00726         }
00727     }
00728 
00729     if (clamp[0] == false && clamp[1] == false)
00730         return false;
00731 
00732     m_new_basis = ComputeSwingMatrix(ax, az);
00733 
00734     delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis);
00735     delta[1] = delta[2]; delta[2] = 0.0;
00736 
00737     return true;
00738 }
00739 
00740 void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta)
00741 {
00742     m_locked[0] = m_locked[1] = true;
00743     jacobian.Lock(m_DoF_id, delta[0]);
00744     jacobian.Lock(m_DoF_id+1, delta[1]);
00745 }
00746 
00747 void IK_QSwingSegment::UpdateAngleApply()
00748 {
00749     m_basis = m_new_basis;
00750 }
00751 
00752 void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
00753 {
00754     if (lmin > lmax)
00755         return;
00756     
00757     // clamp and convert to axis angle parameters
00758     lmin = MT_clamp(lmin, -MT_PI, MT_PI);
00759     lmax = MT_clamp(lmax, -MT_PI, MT_PI);
00760 
00761     lmin = sin(lmin*0.5);
00762     lmax = sin(lmax*0.5);
00763 
00764     // put center of ellispe in the middle between min and max
00765     MT_Scalar offset = 0.5*(lmin + lmax);
00766     //lmax = lmax - offset;
00767 
00768     if (axis == 0) {
00769         m_min[0] = -lmax;
00770         m_max[0] = -lmin;
00771 
00772         m_limit_x = true;
00773         m_offset_x = offset;
00774         m_max_x = lmax;
00775     }
00776     else if (axis == 2) {
00777         m_min[1] = -lmax;
00778         m_max[1] = -lmin;
00779 
00780         m_limit_z = true;
00781         m_offset_z = offset;
00782         m_max_z = lmax;
00783     }
00784 }
00785 
00786 void IK_QSwingSegment::SetWeight(int axis, MT_Scalar weight)
00787 {
00788     if (axis == 0)
00789         m_weight[0] = weight;
00790     else if (axis == 2)
00791         m_weight[1] = weight;
00792 }
00793 
00794 // IK_QElbowSegment
00795 
00796 IK_QElbowSegment::IK_QElbowSegment(int axis)
00797 : IK_QSegment(2, false), m_axis(axis), m_twist(0.0), m_angle(0.0),
00798   m_cos_twist(1.0), m_sin_twist(0.0), m_limit(false), m_limit_twist(false)
00799 {
00800 }
00801 
00802 void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis)
00803 {
00804     m_basis = basis;
00805 
00806     m_twist = ComputeTwist(m_basis);
00807     RemoveTwist(m_basis);
00808     m_angle = EulerAngleFromMatrix(basis, m_axis);
00809 
00810     m_basis = RotationMatrix(m_angle, m_axis)*ComputeTwistMatrix(m_twist);
00811 }
00812 
00813 MT_Vector3 IK_QElbowSegment::Axis(int dof) const
00814 {
00815     if (dof == 0) {
00816         MT_Vector3 v;
00817         if (m_axis == 0)
00818             v = MT_Vector3(m_cos_twist, 0, m_sin_twist);
00819         else
00820             v = MT_Vector3(-m_sin_twist, 0, m_cos_twist);
00821 
00822         return m_global_transform.getBasis() * v;
00823     }
00824     else
00825         return m_global_transform.getBasis().getColumn(1);
00826 }
00827 
00828 bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
00829 {
00830     if (m_locked[0] && m_locked[1])
00831         return false;
00832 
00833     clamp[0] = clamp[1] = false;
00834 
00835     if (!m_locked[0]) {
00836         m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id);
00837 
00838         if (m_limit) {
00839             if (m_new_angle > m_max) {
00840                 delta[0] = m_max - m_angle;
00841                 m_new_angle = m_max;
00842                 clamp[0] = true;
00843             }
00844             else if (m_new_angle < m_min) {
00845                 delta[0] = m_min - m_angle;
00846                 m_new_angle = m_min;
00847                 clamp[0] = true;
00848             }
00849         }
00850     }
00851 
00852     if (!m_locked[1]) {
00853         m_new_twist = m_twist + jacobian.AngleUpdate(m_DoF_id+1);
00854 
00855         if (m_limit_twist) {
00856             if (m_new_twist > m_max_twist) {
00857                 delta[1] = m_max_twist - m_twist;
00858                 m_new_twist = m_max_twist;
00859                 clamp[1] = true;
00860             }
00861             else if (m_new_twist < m_min_twist) {
00862                 delta[1] = m_min_twist - m_twist;
00863                 m_new_twist = m_min_twist;
00864                 clamp[1] = true;
00865             }
00866         }
00867     }
00868 
00869     return (clamp[0] || clamp[1]);
00870 }
00871 
00872 void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
00873 {
00874     if (dof == 0) {
00875         m_locked[0] = true;
00876         jacobian.Lock(m_DoF_id, delta[0]);
00877     }
00878     else {
00879         m_locked[1] = true;
00880         jacobian.Lock(m_DoF_id+1, delta[1]);
00881     }
00882 }
00883 
00884 void IK_QElbowSegment::UpdateAngleApply()
00885 {
00886     m_angle = m_new_angle;
00887     m_twist = m_new_twist;
00888 
00889     m_sin_twist = sin(m_twist);
00890     m_cos_twist = cos(m_twist);
00891 
00892     MT_Matrix3x3 A = RotationMatrix(m_angle, m_axis);
00893     MT_Matrix3x3 T = RotationMatrix(m_sin_twist, m_cos_twist, 1);
00894 
00895     m_basis = A*T;
00896 }
00897 
00898 void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
00899 {
00900     if (lmin > lmax)
00901         return;
00902 
00903     // clamp and convert to axis angle parameters
00904     lmin = MT_clamp(lmin, -MT_PI, MT_PI);
00905     lmax = MT_clamp(lmax, -MT_PI, MT_PI);
00906 
00907     if (axis == 1) {
00908         m_min_twist = lmin;
00909         m_max_twist = lmax;
00910         m_limit_twist = true;
00911     }
00912     else if (axis == m_axis) {
00913         m_min = lmin;
00914         m_max = lmax;
00915         m_limit = true;
00916     }
00917 }
00918 
00919 void IK_QElbowSegment::SetWeight(int axis, MT_Scalar weight)
00920 {
00921     if (axis == m_axis)
00922         m_weight[0] = weight;
00923     else if (axis == 1)
00924         m_weight[1] = weight;
00925 }
00926 
00927 // IK_QTranslateSegment
00928 
00929 IK_QTranslateSegment::IK_QTranslateSegment(int axis1)
00930 : IK_QSegment(1, true)
00931 {
00932     m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false;
00933     m_axis_enabled[axis1] = true;
00934 
00935     m_axis[0] = axis1;
00936 
00937     m_limit[0] = m_limit[1] = m_limit[2] = false;
00938 }
00939 
00940 IK_QTranslateSegment::IK_QTranslateSegment(int axis1, int axis2)
00941 : IK_QSegment(2, true)
00942 {
00943     m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false;
00944     m_axis_enabled[axis1] = true;
00945     m_axis_enabled[axis2] = true;
00946 
00947     m_axis[0] = axis1;
00948     m_axis[1] = axis2;
00949 
00950     m_limit[0] = m_limit[1] = m_limit[2] = false;
00951 }
00952 
00953 IK_QTranslateSegment::IK_QTranslateSegment()
00954 : IK_QSegment(3, true)
00955 {
00956     m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = true;
00957 
00958     m_axis[0] = 0;
00959     m_axis[1] = 1;
00960     m_axis[2] = 2;
00961 
00962     m_limit[0] = m_limit[1] = m_limit[2] = false;
00963 }
00964 
00965 MT_Vector3 IK_QTranslateSegment::Axis(int dof) const
00966 {
00967     return m_global_transform.getBasis().getColumn(m_axis[dof]);
00968 }
00969 
00970 bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
00971 {
00972     int dof_id = m_DoF_id, dof = 0, i, clamped = false;
00973 
00974     MT_Vector3 dx(0.0, 0.0, 0.0);
00975 
00976     for (i = 0; i < 3; i++) {
00977         if (!m_axis_enabled[i]) {
00978             m_new_translation[i] = m_translation[i];
00979             continue;
00980         }
00981 
00982         clamp[dof] = false;
00983 
00984         if (!m_locked[dof]) {
00985             m_new_translation[i] = m_translation[i] + jacobian.AngleUpdate(dof_id);
00986 
00987             if (m_limit[i]) {
00988                 if (m_new_translation[i] > m_max[i]) {
00989                     delta[dof] = m_max[i] - m_translation[i];
00990                     m_new_translation[i] = m_max[i];
00991                     clamped = clamp[dof] = true;
00992                 }
00993                 else if (m_new_translation[i] < m_min[i]) {
00994                     delta[dof] = m_min[i] - m_translation[i];
00995                     m_new_translation[i] = m_min[i];
00996                     clamped = clamp[dof] = true;
00997                 }
00998             }
00999         }
01000 
01001         dof_id++;
01002         dof++;
01003     }
01004 
01005     return clamped;
01006 }
01007 
01008 void IK_QTranslateSegment::UpdateAngleApply()
01009 {
01010     m_translation = m_new_translation;
01011 }
01012 
01013 void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
01014 {
01015     m_locked[dof] = true;
01016     jacobian.Lock(m_DoF_id+dof, delta[dof]);
01017 }
01018 
01019 void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight)
01020 {
01021     int i;
01022 
01023     for (i = 0; i < m_num_DoF; i++)
01024         if (m_axis[i] == axis)
01025             m_weight[i] = weight;
01026 }
01027 
01028 void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
01029 {
01030     if (lmax < lmin)
01031         return;
01032 
01033     m_min[axis]= lmin;
01034     m_max[axis]= lmax;
01035     m_limit[axis]= true;
01036 }
01037 
01038 void IK_QTranslateSegment::Scale(float scale)
01039 {
01040     int i;
01041 
01042     IK_QSegment::Scale(scale);
01043 
01044     for (i = 0; i < 3; i++) {
01045         m_min[0] *= scale;
01046         m_max[1] *= scale;
01047     }
01048 
01049     m_new_translation *= scale;
01050 }
01051