lljointsolverrp3.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:12k
- /**
- * @file lljointsolverrp3.cpp
- * @brief Implementation of LLJointSolverRP3 class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- //-----------------------------------------------------------------------------
- // Header Files
- //-----------------------------------------------------------------------------
- #include "linden_common.h"
- #include "lljointsolverrp3.h"
- #include "llmath.h"
- #define F_EPSILON 0.00001f
- //-----------------------------------------------------------------------------
- // Constructor
- //-----------------------------------------------------------------------------
- LLJointSolverRP3::LLJointSolverRP3()
- {
- mJointA = NULL;
- mJointB = NULL;
- mJointC = NULL;
- mJointGoal = NULL;
- mLengthAB = 1.0f;
- mLengthBC = 1.0f;
- mPoleVector.setVec( 1.0f, 0.0f, 0.0f );
- mbUseBAxis = FALSE;
- mTwist = 0.0f;
- mFirstTime = TRUE;
- }
- //-----------------------------------------------------------------------------
- // Destructor
- //-----------------------------------------------------------------------------
- /*virtual*/ LLJointSolverRP3::~LLJointSolverRP3()
- {
- }
- //-----------------------------------------------------------------------------
- // setupJoints()
- //-----------------------------------------------------------------------------
- void LLJointSolverRP3::setupJoints( LLJoint* jointA,
- LLJoint* jointB,
- LLJoint* jointC,
- LLJoint* jointGoal )
- {
- mJointA = jointA;
- mJointB = jointB;
- mJointC = jointC;
- mJointGoal = jointGoal;
- mLengthAB = mJointB->getPosition().magVec();
- mLengthBC = mJointC->getPosition().magVec();
- mJointABaseRotation = jointA->getRotation();
- mJointBBaseRotation = jointB->getRotation();
- }
- //-----------------------------------------------------------------------------
- // getPoleVector()
- //-----------------------------------------------------------------------------
- const LLVector3& LLJointSolverRP3::getPoleVector()
- {
- return mPoleVector;
- }
- //-----------------------------------------------------------------------------
- // setPoleVector()
- //-----------------------------------------------------------------------------
- void LLJointSolverRP3::setPoleVector( const LLVector3& poleVector )
- {
- mPoleVector = poleVector;
- mPoleVector.normVec();
- }
- //-----------------------------------------------------------------------------
- // setPoleVector()
- //-----------------------------------------------------------------------------
- void LLJointSolverRP3::setBAxis( const LLVector3& bAxis )
- {
- mBAxis = bAxis;
- mBAxis.normVec();
- mbUseBAxis = TRUE;
- }
- //-----------------------------------------------------------------------------
- // getTwist()
- //-----------------------------------------------------------------------------
- F32 LLJointSolverRP3::getTwist()
- {
- return mTwist;
- }
- //-----------------------------------------------------------------------------
- // setTwist()
- //-----------------------------------------------------------------------------
- void LLJointSolverRP3::setTwist( F32 twist )
- {
- mTwist = twist;
- }
- //-----------------------------------------------------------------------------
- // solve()
- //-----------------------------------------------------------------------------
- void LLJointSolverRP3::solve()
- {
- // llinfos << llendl;
- // llinfos << "LLJointSolverRP3::solve()" << llendl;
- //-------------------------------------------------------------------------
- // setup joints in their base rotations
- //-------------------------------------------------------------------------
- mJointA->setRotation( mJointABaseRotation );
- mJointB->setRotation( mJointBBaseRotation );
- //-------------------------------------------------------------------------
- // get joint positions in world space
- //-------------------------------------------------------------------------
- LLVector3 aPos = mJointA->getWorldPosition();
- LLVector3 bPos = mJointB->getWorldPosition();
- LLVector3 cPos = mJointC->getWorldPosition();
- LLVector3 gPos = mJointGoal->getWorldPosition();
- // llinfos << "bPosLocal = " << mJointB->getPosition() << llendl;
- // llinfos << "cPosLocal = " << mJointC->getPosition() << llendl;
- // llinfos << "bRotLocal = " << mJointB->getRotation() << llendl;
- // llinfos << "cRotLocal = " << mJointC->getRotation() << llendl;
- // llinfos << "aPos : " << aPos << llendl;
- // llinfos << "bPos : " << bPos << llendl;
- // llinfos << "cPos : " << cPos << llendl;
- // llinfos << "gPos : " << gPos << llendl;
- //-------------------------------------------------------------------------
- // get the poleVector in world space
- //-------------------------------------------------------------------------
- LLMatrix4 worldJointAParentMat;
- if ( mJointA->getParent() )
- {
- worldJointAParentMat = mJointA->getParent()->getWorldMatrix();
- }
- LLVector3 poleVec = rotate_vector( mPoleVector, worldJointAParentMat );
- //-------------------------------------------------------------------------
- // compute the following:
- // vector from A to B
- // vector from B to C
- // vector from A to C
- // vector from A to G (goal)
- //-------------------------------------------------------------------------
- LLVector3 abVec = bPos - aPos;
- LLVector3 bcVec = cPos - bPos;
- LLVector3 acVec = cPos - aPos;
- LLVector3 agVec = gPos - aPos;
- // llinfos << "abVec : " << abVec << llendl;
- // llinfos << "bcVec : " << bcVec << llendl;
- // llinfos << "acVec : " << acVec << llendl;
- // llinfos << "agVec : " << agVec << llendl;
- //-------------------------------------------------------------------------
- // compute needed lengths of those vectors
- //-------------------------------------------------------------------------
- F32 abLen = abVec.magVec();
- F32 bcLen = bcVec.magVec();
- F32 agLen = agVec.magVec();
- // llinfos << "abLen : " << abLen << llendl;
- // llinfos << "bcLen : " << bcLen << llendl;
- // llinfos << "agLen : " << agLen << llendl;
- //-------------------------------------------------------------------------
- // compute component vector of (A->B) orthogonal to (A->C)
- //-------------------------------------------------------------------------
- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
- // llinfos << "abacCompOrthoVec : " << abacCompOrthoVec << llendl;
- //-------------------------------------------------------------------------
- // compute the normal of the original ABC plane (and store for later)
- //-------------------------------------------------------------------------
- LLVector3 abcNorm;
- if (!mbUseBAxis)
- {
- if( are_parallel(abVec, bcVec, 0.001f) )
- {
- // the current solution is maxed out, so we use the axis that is
- // orthogonal to both poleVec and A->B
- if ( are_parallel(poleVec, abVec, 0.001f) )
- {
- // ACK! the problem is singular
- if ( are_parallel(poleVec, agVec, 0.001f) )
- {
- // the solutions is also singular
- return;
- }
- else
- {
- abcNorm = poleVec % agVec;
- }
- }
- else
- {
- abcNorm = poleVec % abVec;
- }
- }
- else
- {
- abcNorm = abVec % bcVec;
- }
- }
- else
- {
- abcNorm = mBAxis * mJointB->getWorldRotation();
- }
- //-------------------------------------------------------------------------
- // compute rotation of B
- //-------------------------------------------------------------------------
- // angle between A->B and B->C
- F32 abbcAng = angle_between(abVec, bcVec);
- // vector orthogonal to A->B and B->C
- LLVector3 abbcOrthoVec = abVec % bcVec;
- if (abbcOrthoVec.magVecSquared() < 0.001f)
- {
- abbcOrthoVec = poleVec % abVec;
- abacCompOrthoVec = poleVec;
- }
- abbcOrthoVec.normVec();
- F32 agLenSq = agLen * agLen;
- // angle arm for extension
- F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen);
- if (cosTheta > 1.0f)
- cosTheta = 1.0f;
- else if (cosTheta < -1.0f)
- cosTheta = -1.0f;
- F32 theta = acos(cosTheta);
- LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
- // llinfos << "abbcAng : " << abbcAng << llendl;
- // llinfos << "abbcOrthoVec : " << abbcOrthoVec << llendl;
- // llinfos << "agLenSq : " << agLenSq << llendl;
- // llinfos << "cosTheta : " << cosTheta << llendl;
- // llinfos << "theta : " << theta << llendl;
- // llinfos << "bRot : " << bRot << llendl;
- // llinfos << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << llendl;
- //-------------------------------------------------------------------------
- // compute rotation that rotates new A->C to A->G
- //-------------------------------------------------------------------------
- // rotate B->C by bRot
- bcVec = bcVec * bRot;
- // update A->C
- acVec = abVec + bcVec;
- LLQuaternion cgRot;
- cgRot.shortestArc( acVec, agVec );
- // llinfos << "bcVec : " << bcVec << llendl;
- // llinfos << "acVec : " << acVec << llendl;
- // llinfos << "cgRot : " << cgRot << llendl;
- // update A->B and B->C with rotation from C to G
- abVec = abVec * cgRot;
- bcVec = bcVec * cgRot;
- abcNorm = abcNorm * cgRot;
- acVec = abVec + bcVec;
- //-------------------------------------------------------------------------
- // compute the normal of the APG plane
- //-------------------------------------------------------------------------
- if (are_parallel(agVec, poleVec, 0.001f))
- {
- // the solution plane is undefined ==> we're done
- return;
- }
- LLVector3 apgNorm = poleVec % agVec;
- apgNorm.normVec();
- if (!mbUseBAxis)
- {
- //---------------------------------------------------------------------
- // compute the normal of the new ABC plane
- // (only necessary if we're NOT using mBAxis)
- //---------------------------------------------------------------------
- if( are_parallel(abVec, bcVec, 0.001f) )
- {
- // G is either too close or too far away
- // we'll use the old ABCnormal
- }
- else
- {
- abcNorm = abVec % bcVec;
- }
- abcNorm.normVec();
- }
- //-------------------------------------------------------------------------
- // calcuate plane rotation
- //-------------------------------------------------------------------------
- LLQuaternion pRot;
- if ( are_parallel( abcNorm, apgNorm, 0.001f) )
- {
- if (abcNorm * apgNorm < 0.0f)
- {
- // we must be PI radians off ==> rotate by PI around agVec
- pRot.setQuat(F_PI, agVec);
- }
- else
- {
- // we're done
- }
- }
- else
- {
- pRot.shortestArc( abcNorm, apgNorm );
- }
- // llinfos << "abcNorm = " << abcNorm << llendl;
- // llinfos << "apgNorm = " << apgNorm << llendl;
- // llinfos << "pRot = " << pRot << llendl;
- //-------------------------------------------------------------------------
- // compute twist rotation
- //-------------------------------------------------------------------------
- LLQuaternion twistRot( mTwist, agVec );
- // llinfos << "twist : " << mTwist*180.0/F_PI << llendl;
- // llinfos << "agNormVec: " << agNormVec << llendl;
- // llinfos << "twistRot : " << twistRot << llendl;
- //-------------------------------------------------------------------------
- // compute rotation of A
- //-------------------------------------------------------------------------
- LLQuaternion aRot = cgRot * pRot * twistRot;
- //-------------------------------------------------------------------------
- // apply the rotations
- //-------------------------------------------------------------------------
- mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot );
- mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot );
- }
- // End