|
Blender
V2.59
|
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