예제 #1
0
bool AwQuaternion::getAxisAngle(AwVector &axis, double &theta) const
//
//	Description:
//		This function converts this quaternion into a user understandable
//		representation.  That is, the quaternion is represented as a pivot
//		vector 'axis' and a rotation 'theta' (in radians) about that pivot
//		vector.
//
//	Returns:
//		true	- angle != 0
//		false	- angle == 0	(uses arbitrary axis, if given axis not valid)
//
//	Notes:
//		If the identity unit quaternion is attempted to be converted to the
//		pivot axis and angle representation it will be set to a zero degree
//		rotation about the axis that was passed in.  (Note that any axis will
//		do, since an infinity of axis with rotation of zero satisfy the identity
//		rotation.)  If the axis is zero length, then an arbitrary axis will be
//		chosen (z-axis).
//
{
	bool result;
	double inverseOfSinThetaByTwo, thetaExtended;
	
	if (::equivalent(w, (double) 1.0)) {
		theta = 0.0;
		if (axis.length() < kDoubleEpsilon) {
			//  Passed in axis invalid, choose an arbitrary axis.
			axis.set(0.0,0.0,1.0);
		}
		result = false;
	}
	else {
		thetaExtended = acos(clamp(w,-1.0,1.0));
		theta = thetaExtended * 2.0;
		
		inverseOfSinThetaByTwo = 1.0 / sin(thetaExtended);
		axis.x = x * inverseOfSinThetaByTwo;
		axis.y = y * inverseOfSinThetaByTwo;
		axis.z = z * inverseOfSinThetaByTwo;

		result = true;
	}

	return result;
}
예제 #2
0
AwQuaternion::AwQuaternion(const AwVector &a, const AwVector &b)
//
//	Description:
//		This constructor creates a new quaternion that will rotate vector
//		a into vector b about their mutually perpendicular axis. (if one
//		exists)
//
: w(1.0), x(0.0), y(0.0), z(0.0)
{
	double factor = a.length() * b.length();
	
	if (fabs(factor) > kFloatEpsilon) {
		// Vectors have length > 0
		AwVector pivotVector;
		double dot = a.dotProduct(b) / factor;
		double theta = acos(clamp(dot, -1.0, 1.0));
		
		pivotVector = a^b;
        if (dot < 0.0 && pivotVector.length() < kFloatEpsilon) {
			// Vectors parallel and opposite direction, therefore a rotation
			// of 180 degrees about any vector perpendicular to this vector
			// will rotate vector a onto vector b.
			//
			// The following guarantees the dot-product will be 0.0.
			//
		    size_t dominantIndex = a.dominantAxis();
			pivotVector[dominantIndex] = -a[(dominantIndex+1)%3];
			pivotVector[(dominantIndex+1)%3] = a[dominantIndex];
			pivotVector[(dominantIndex+2)%3] = 0.0;
		}		
		setAxisAngle(pivotVector, theta);
	}
}
예제 #3
0
void solveIK(const AwPoint &startJointPos,
			 const AwPoint &midJointPos,
			 const AwPoint &effectorPos,
			 const AwPoint &handlePos,
			 const AwVector &poleVector,
			 double twistValue,
			 AwQuaternion &qStart,
			 AwQuaternion &qMid)
//
// This is method that actually computes the IK solution.
//
{
	// vector from startJoint to midJoint
	AwVector vector1 = midJointPos - startJointPos;
	// vector from midJoint to effector
	AwVector vector2 = effectorPos - midJointPos;
	// vector from startJoint to handle
	AwVector vectorH = handlePos - startJointPos;
	// vector from startJoint to effector
	AwVector vectorE = effectorPos - startJointPos;
	// lengths of those vectors
	double length1 = vector1.length();
	double length2 = vector2.length();
	double lengthH = vectorH.length();
	// component of the vector1 orthogonal to the vectorE
	AwVector vectorO =
		vector1 - vectorE*((vector1*vectorE)/(vectorE*vectorE));

	//////////////////////////////////////////////////////////////////
	// calculate q12 which solves for the midJoint rotation
	//////////////////////////////////////////////////////////////////
	// angle between vector1 and vector2
	double vectorAngle12 = vector1.angle(vector2);
	// vector orthogonal to vector1 and 2
	AwVector vectorCross12 = vector1^vector2;
	double lengthHsquared = lengthH*lengthH;
	// angle for arm extension 
	double cos_theta = 
		(lengthHsquared - length1*length1 - length2*length2)
		/(2*length1*length2);
	if (cos_theta > 1) 
		cos_theta = 1;
	else if (cos_theta < -1) 
		cos_theta = -1;
	double theta = acos(cos_theta);
	// quaternion for arm extension
	AwQuaternion q12(theta - vectorAngle12, vectorCross12);
	
	//////////////////////////////////////////////////////////////////
	// calculate qEH which solves for effector rotating onto the handle
	//////////////////////////////////////////////////////////////////
	// vector2 with quaternion q12 applied
	vector2 = vector2.rotateBy(q12);
	// vectorE with quaternion q12 applied
	vectorE = vector1 + vector2;
	// quaternion for rotating the effector onto the handle
	AwQuaternion qEH(vectorE, vectorH);

	//////////////////////////////////////////////////////////////////
	// calculate qNP which solves for the rotate plane
	//////////////////////////////////////////////////////////////////
	// vector1 with quaternion qEH applied
	vector1 = vector1.rotateBy(qEH);
	if (vector1.isParallel(vectorH))
		// singular case, use orthogonal component instead
		vector1 = vectorO.rotateBy(qEH);
	// quaternion for rotate plane
	AwQuaternion qNP;
	if (!poleVector.isParallel(vectorH) && (lengthHsquared != 0)) {
		// component of vector1 orthogonal to vectorH
		AwVector vectorN = 
			vector1 - vectorH*((vector1*vectorH)/lengthHsquared);
		// component of pole vector orthogonal to vectorH
		AwVector vectorP = 
			poleVector - vectorH*((poleVector*vectorH)/lengthHsquared);
		double dotNP = (vectorN*vectorP)/(vectorN.length()*vectorP.length());
		if (absoluteValue(dotNP + 1.0) < kEpsilon) {
			// singular case, rotate halfway around vectorH
			AwQuaternion qNP1(kPi, vectorH);
			qNP = qNP1;
		}
		else {
			AwQuaternion qNP2(vectorN, vectorP);
			qNP = qNP2;
		}
	}

	//////////////////////////////////////////////////////////////////
	// calculate qTwist which adds the twist
	//////////////////////////////////////////////////////////////////
	AwQuaternion qTwist(twistValue, vectorH);

	// quaternion for the mid joint
	qMid = q12;	
	// concatenate the quaternions for the start joint
	qStart = qEH*qNP*qTwist;
}