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