Blender V2.61 - r43446
|
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