* Adjustment: Update Bullet version to 3.24.

This commit is contained in:
Robert MacGregor 2022-06-27 10:01:08 -04:00
parent 35de012ee7
commit 4a3f31df2a
6148 changed files with 2112532 additions and 56873 deletions

View file

@ -0,0 +1,15 @@
INCLUDE_DIRECTORIES(
.
)
FILE(GLOB BussIK_SRCS "*.cpp" )
FILE(GLOB BussIK_HDRS "*.h" )
ADD_LIBRARY(BussIK ${BussIK_SRCS} ${BussIK_HDRS})
INSTALL(TARGETS BussIK
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX})

View file

@ -0,0 +1,790 @@
/*
*
* Inverse Kinematics software, with several solvers including
* Selectively Damped Least Squares Method
* Damped Least Squares Method
* Pure Pseudoinverse Method
* Jacobian Transpose Method
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/index.html
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <iostream>
using namespace std;
#include "Jacobian.h"
void Arrow(const VectorR3& tail, const VectorR3& head);
//extern RestPositionOn;
//extern VectorR3 target1[];
// Optimal damping values have to be determined in an ad hoc manner (Yuck!)
const double Jacobian::DefaultDampingLambda = 0.6; // Optimal for the "Y" shape (any lower gives jitter)
//const double Jacobian::DefaultDampingLambda = 1.1; // Optimal for the DLS "double Y" shape (any lower gives jitter)
// const double Jacobian::DefaultDampingLambda = 0.7; // Optimal for the DLS "double Y" shape with distance clamping (lower gives jitter)
const double Jacobian::PseudoInverseThresholdFactor = 0.01;
const double Jacobian::MaxAngleJtranspose = 30.0 * DegreesToRadians;
const double Jacobian::MaxAnglePseudoinverse = 5.0 * DegreesToRadians;
const double Jacobian::MaxAngleDLS = 45.0 * DegreesToRadians;
const double Jacobian::MaxAngleSDLS = 45.0 * DegreesToRadians;
const double Jacobian::BaseMaxTargetDist = 0.4;
Jacobian::Jacobian(Tree* tree)
{
m_tree = tree;
m_nEffector = tree->GetNumEffector();
nJoint = tree->GetNumJoint();
nRow = 3 * m_nEffector; // Include only the linear part
nCol = nJoint;
Jend.SetSize(nRow, nCol); // The Jocobian matrix
Jend.SetZero();
Jtarget.SetSize(nRow, nCol); // The Jacobian matrix based on target positions
Jtarget.SetZero();
SetJendActive();
U.SetSize(nRow, nRow); // The U matrix for SVD calculations
w.SetLength(Min(nRow, nCol));
V.SetSize(nCol, nCol); // The V matrix for SVD calculations
dS.SetLength(nRow); // (Target positions) - (End effector positions)
dTheta.SetLength(nCol); // Changes in joint angles
dPreTheta.SetLength(nCol);
// Used by Jacobian transpose method & DLS & SDLS
dT1.SetLength(nRow); // Linearized change in end effector positions based on dTheta
// Used by the Selectively Damped Least Squares Method
//dT.SetLength(nRow);
dSclamp.SetLength(m_nEffector);
errorArray.SetLength(m_nEffector);
Jnorms.SetSize(m_nEffector, nCol); // Holds the norms of the active J matrix
Reset();
}
Jacobian::Jacobian(bool useAngularJacobian, int nDof, int numEndEffectors)
{
m_tree = 0;
m_nEffector = numEndEffectors;
if (useAngularJacobian)
{
nRow = 2 * 3 * m_nEffector; // Include both linear and angular part
}
else
{
nRow = 3 * m_nEffector; // Include only the linear part
}
nCol = nDof;
Jend.SetSize(nRow, nCol); // The Jocobian matrix
Jend.SetZero();
Jtarget.SetSize(nRow, nCol); // The Jacobian matrix based on target positions
Jtarget.SetZero();
SetJendActive();
U.SetSize(nRow, nRow); // The U matrix for SVD calculations
w.SetLength(Min(nRow, nCol));
V.SetSize(nCol, nCol); // The V matrix for SVD calculations
dS.SetLength(nRow); // (Target positions) - (End effector positions)
dTheta.SetLength(nCol); // Changes in joint angles
dPreTheta.SetLength(nCol);
// Used by Jacobian transpose method & DLS & SDLS
dT1.SetLength(nRow); // Linearized change in end effector positions based on dTheta
// Used by the Selectively Damped Least Squares Method
//dT.SetLength(nRow);
dSclamp.SetLength(m_nEffector);
errorArray.SetLength(m_nEffector);
Jnorms.SetSize(m_nEffector, nCol); // Holds the norms of the active J matrix
Reset();
}
void Jacobian::Reset()
{
// Used by Damped Least Squares Method
DampingLambda = DefaultDampingLambda;
DampingLambdaSq = Square(DampingLambda);
// DampingLambdaSDLS = 1.5*DefaultDampingLambda;
dSclamp.Fill(HUGE_VAL);
}
// Compute the deltaS vector, dS, (the error in end effector positions
// Compute the J and K matrices (the Jacobians)
void Jacobian::ComputeJacobian(VectorR3* targets)
{
if (m_tree == 0)
return;
// Traverse tree to find all end effectors
VectorR3 temp;
Node* n = m_tree->GetRoot();
while (n)
{
if (n->IsEffector())
{
int i = n->GetEffectorNum();
const VectorR3& targetPos = targets[i];
// Compute the delta S value (differences from end effectors to target positions.
temp = targetPos;
temp -= n->GetS();
dS.SetTriple(i, temp);
// Find all ancestors (they will usually all be joints)
// Set the corresponding entries in the Jacobians J, K.
Node* m = m_tree->GetParent(n);
while (m)
{
int j = m->GetJointNum();
assert(0 <= i && i < m_nEffector && 0 <= j && j < nJoint);
if (m->IsFrozen())
{
Jend.SetTriple(i, j, VectorR3::Zero);
Jtarget.SetTriple(i, j, VectorR3::Zero);
}
else
{
temp = m->GetS(); // joint pos.
temp -= n->GetS(); // -(end effector pos. - joint pos.)
temp *= m->GetW(); // cross product with joint rotation axis
Jend.SetTriple(i, j, temp);
temp = m->GetS(); // joint pos.
temp -= targetPos; // -(target pos. - joint pos.)
temp *= m->GetW(); // cross product with joint rotation axis
Jtarget.SetTriple(i, j, temp);
}
m = m_tree->GetParent(m);
}
}
n = m_tree->GetSuccessor(n);
}
}
void Jacobian::SetJendTrans(MatrixRmn& J)
{
Jend.SetSize(J.GetNumRows(), J.GetNumColumns());
Jend.LoadAsSubmatrix(J);
}
void Jacobian::SetDeltaS(VectorRn& S)
{
dS.Set(S);
}
// The delta theta values have been computed in dTheta array
// Apply the delta theta values to the joints
// Nothing is done about joint limits for now.
void Jacobian::UpdateThetas()
{
// Traverse the tree to find all joints
// Update the joint angles
Node* n = m_tree->GetRoot();
while (n)
{
if (n->IsJoint())
{
int i = n->GetJointNum();
n->AddToTheta(dTheta[i]);
}
n = m_tree->GetSuccessor(n);
}
// Update the positions and rotation axes of all joints/effectors
m_tree->Compute();
}
void Jacobian::UpdateThetaDot()
{
if (m_tree == 0)
return;
// Traverse the tree to find all joints
// Update the joint angles
Node* n = m_tree->GetRoot();
while (n)
{
if (n->IsJoint())
{
int i = n->GetJointNum();
n->UpdateTheta(dTheta[i]);
}
n = m_tree->GetSuccessor(n);
}
// Update the positions and rotation axes of all joints/effectors
m_tree->Compute();
}
void Jacobian::CalcDeltaThetas(MatrixRmn& AugMat)
{
switch (CurrentUpdateMode)
{
case JACOB_Undefined:
ZeroDeltaThetas();
break;
case JACOB_JacobianTranspose:
CalcDeltaThetasTranspose();
break;
case JACOB_PseudoInverse:
CalcDeltaThetasPseudoinverse();
break;
case JACOB_DLS:
CalcDeltaThetasDLS(AugMat);
break;
case JACOB_SDLS:
CalcDeltaThetasSDLS();
break;
}
}
void Jacobian::ZeroDeltaThetas()
{
dTheta.SetZero();
}
// Find the delta theta values using inverse Jacobian method
// Uses a greedy method to decide scaling factor
void Jacobian::CalcDeltaThetasTranspose()
{
const MatrixRmn& J = ActiveJacobian();
J.MultiplyTranspose(dS, dTheta);
// Scale back the dTheta values greedily
J.Multiply(dTheta, dT1); // dT = J * dTheta
double alpha = Dot(dS, dT1) / dT1.NormSq();
assert(alpha > 0.0);
// Also scale back to be have max angle change less than MaxAngleJtranspose
double maxChange = dTheta.MaxAbs();
double beta = MaxAngleJtranspose / maxChange;
dTheta *= Min(alpha, beta);
}
void Jacobian::CalcDeltaThetasPseudoinverse()
{
MatrixRmn& J = const_cast<MatrixRmn&>(ActiveJacobian());
// Compute Singular Value Decomposition
// This an inefficient way to do Pseudoinverse, but it is convenient since we need SVD anyway
J.ComputeSVD(U, w, V);
// Next line for debugging only
assert(J.DebugCheckSVD(U, w, V));
// Calculate response vector dTheta that is the DLS solution.
// Delta target values are the dS values
// We multiply by Moore-Penrose pseudo-inverse of the J matrix
double pseudoInverseThreshold = PseudoInverseThresholdFactor * w.MaxAbs();
long diagLength = w.GetLength();
double* wPtr = w.GetPtr();
dTheta.SetZero();
for (long i = 0; i < diagLength; i++)
{
double dotProdCol = U.DotProductColumn(dS, i); // Dot product with i-th column of U
double alpha = *(wPtr++);
if (fabs(alpha) > pseudoInverseThreshold)
{
alpha = 1.0 / alpha;
MatrixRmn::AddArrayScale(V.GetNumRows(), V.GetColumnPtr(i), 1, dTheta.GetPtr(), 1, dotProdCol * alpha);
}
}
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAnglePseudoinverse)
{
dTheta *= MaxAnglePseudoinverse / maxChange;
}
}
void Jacobian::CalcDeltaThetasDLSwithNullspace(const VectorRn& desiredV, MatrixRmn& AugMat)
{
const MatrixRmn& J = ActiveJacobian();
MatrixRmn::MultiplyTranspose(J, J, U); // U = J * (J^T)
U.AddToDiagonal(DampingLambdaSq);
// Use the next four lines instead of the succeeding two lines for the DLS method with clamped error vector e.
// CalcdTClampedFromdS();
// VectorRn dTextra(3*m_nEffector);
// U.Solve( dT, &dTextra );
// J.MultiplyTranspose( dTextra, dTheta );
// Use these two lines for the traditional DLS method
U.Solve(dS, &dT1, AugMat);
J.MultiplyTranspose(dT1, dTheta);
// Compute JInv in damped least square form
MatrixRmn UInv(U.GetNumRows(), U.GetNumColumns());
U.ComputeInverse(UInv);
assert(U.DebugCheckInverse(UInv));
MatrixRmn JInv(J.GetNumColumns(), J.GetNumRows());
MatrixRmn::TransposeMultiply(J, UInv, JInv);
// Compute null space projection
MatrixRmn JInvJ(J.GetNumColumns(), J.GetNumColumns());
MatrixRmn::Multiply(JInv, J, JInvJ);
MatrixRmn P(J.GetNumColumns(), J.GetNumColumns());
P.SetIdentity();
P -= JInvJ;
// Compute null space velocity
VectorRn nullV(J.GetNumColumns());
P.Multiply(desiredV, nullV);
// Compute residual
VectorRn residual(J.GetNumRows());
J.Multiply(nullV, residual);
// TODO: Use residual to set the null space term coefficient adaptively.
//printf("residual: %f\n", residual.Norm());
// Add null space velocity
dTheta += nullV;
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAngleDLS)
{
dTheta *= MaxAngleDLS / maxChange;
}
}
void Jacobian::CalcDeltaThetasDLS(MatrixRmn& AugMat)
{
const MatrixRmn& J = ActiveJacobian();
MatrixRmn::MultiplyTranspose(J, J, U); // U = J * (J^T)
U.AddToDiagonal(DampingLambdaSq);
// Use the next four lines instead of the succeeding two lines for the DLS method with clamped error vector e.
// CalcdTClampedFromdS();
// VectorRn dTextra(3*m_nEffector);
// U.Solve( dT, &dTextra );
// J.MultiplyTranspose( dTextra, dTheta );
// Use these two lines for the traditional DLS method
U.Solve(dS, &dT1, AugMat);
J.MultiplyTranspose(dT1, dTheta);
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAngleDLS)
{
dTheta *= MaxAngleDLS / maxChange;
}
}
void Jacobian::CalcDeltaThetasDLS2(const VectorRn& dVec, MatrixRmn& AugMat)
{
const MatrixRmn& J = ActiveJacobian();
U.SetSize(J.GetNumColumns(), J.GetNumColumns());
MatrixRmn::TransposeMultiply(J, J, U);
U.AddToDiagonal(dVec);
dT1.SetLength(J.GetNumColumns());
J.MultiplyTranspose(dS, dT1);
U.Solve(dT1, &dTheta, AugMat);
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAngleDLS)
{
dTheta *= MaxAngleDLS / maxChange;
}
}
void Jacobian::CalcDeltaThetasDLSwithSVD()
{
const MatrixRmn& J = ActiveJacobian();
// Compute Singular Value Decomposition
// This an inefficient way to do DLS, but it is convenient since we need SVD anyway
J.ComputeSVD(U, w, V);
// Next line for debugging only
assert(J.DebugCheckSVD(U, w, V));
// Calculate response vector dTheta that is the DLS solution.
// Delta target values are the dS values
// We multiply by DLS inverse of the J matrix
long diagLength = w.GetLength();
double* wPtr = w.GetPtr();
dTheta.SetZero();
for (long i = 0; i < diagLength; i++)
{
double dotProdCol = U.DotProductColumn(dS, i); // Dot product with i-th column of U
double alpha = *(wPtr++);
alpha = alpha / (Square(alpha) + DampingLambdaSq);
MatrixRmn::AddArrayScale(V.GetNumRows(), V.GetColumnPtr(i), 1, dTheta.GetPtr(), 1, dotProdCol * alpha);
}
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAngleDLS)
{
dTheta *= MaxAngleDLS / maxChange;
}
}
void Jacobian::CalcDeltaThetasSDLS()
{
const MatrixRmn& J = ActiveJacobian();
// Compute Singular Value Decomposition
J.ComputeSVD(U, w, V);
// Next line for debugging only
assert(J.DebugCheckSVD(U, w, V));
// Calculate response vector dTheta that is the SDLS solution.
// Delta target values are the dS values
int nRows = J.GetNumRows();
int numEndEffectors = m_tree->GetNumEffector();
int nCols = J.GetNumColumns();
dTheta.SetZero();
// Calculate the norms of the 3-vectors in the Jacobian
long i;
const double* jx = J.GetPtr();
double* jnx = Jnorms.GetPtr();
for (i = nCols * numEndEffectors; i > 0; i--)
{
double accumSq = Square(*(jx++));
accumSq += Square(*(jx++));
accumSq += Square(*(jx++));
*(jnx++) = sqrt(accumSq);
}
// Clamp the dS values
CalcdTClampedFromdS();
// Loop over each singular vector
for (i = 0; i < nRows; i++)
{
double wiInv = w[i];
if (NearZero(wiInv, 1.0e-10))
{
continue;
}
wiInv = 1.0 / wiInv;
double N = 0.0; // N is the quasi-1-norm of the i-th column of U
double alpha = 0.0; // alpha is the dot product of dT and the i-th column of U
const double* dTx = dT1.GetPtr();
const double* ux = U.GetColumnPtr(i);
long j;
for (j = numEndEffectors; j > 0; j--)
{
double tmp;
alpha += (*ux) * (*(dTx++));
tmp = Square(*(ux++));
alpha += (*ux) * (*(dTx++));
tmp += Square(*(ux++));
alpha += (*ux) * (*(dTx++));
tmp += Square(*(ux++));
N += sqrt(tmp);
}
// M is the quasi-1-norm of the response to angles changing according to the i-th column of V
// Then is multiplied by the wiInv value.
double M = 0.0;
double* vx = V.GetColumnPtr(i);
jnx = Jnorms.GetPtr();
for (j = nCols; j > 0; j--)
{
double accum = 0.0;
for (long k = numEndEffectors; k > 0; k--)
{
accum += *(jnx++);
}
M += fabs((*(vx++))) * accum;
}
M *= fabs(wiInv);
double gamma = MaxAngleSDLS;
if (N < M)
{
gamma *= N / M; // Scale back maximum permissable joint angle
}
// Calculate the dTheta from pure pseudoinverse considerations
double scale = alpha * wiInv; // This times i-th column of V is the psuedoinverse response
dPreTheta.LoadScaled(V.GetColumnPtr(i), scale);
// Now rescale the dTheta values.
double max = dPreTheta.MaxAbs();
double rescale = (gamma) / (gamma + max);
dTheta.AddScaled(dPreTheta, rescale);
/*if ( gamma<max) {
dTheta.AddScaled( dPreTheta, gamma/max );
}
else {
dTheta += dPreTheta;
}*/
}
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if (maxChange > MaxAngleSDLS)
{
dTheta *= MaxAngleSDLS / (MaxAngleSDLS + maxChange);
//dTheta *= MaxAngleSDLS/maxChange;
}
}
void Jacobian::CalcdTClampedFromdS()
{
long len = dS.GetLength();
long j = 0;
for (long i = 0; i < len; i += 3, j++)
{
double normSq = Square(dS[i]) + Square(dS[i + 1]) + Square(dS[i + 2]);
if (normSq > Square(dSclamp[j]))
{
double factor = dSclamp[j] / sqrt(normSq);
dT1[i] = dS[i] * factor;
dT1[i + 1] = dS[i + 1] * factor;
dT1[i + 2] = dS[i + 2] * factor;
}
else
{
dT1[i] = dS[i];
dT1[i + 1] = dS[i + 1];
dT1[i + 2] = dS[i + 2];
}
}
}
double Jacobian::UpdateErrorArray(VectorR3* targets)
{
double totalError = 0.0;
// Traverse tree to find all end effectors
VectorR3 temp;
Node* n = m_tree->GetRoot();
while (n)
{
if (n->IsEffector())
{
int i = n->GetEffectorNum();
const VectorR3& targetPos = targets[i];
temp = targetPos;
temp -= n->GetS();
double err = temp.Norm();
errorArray[i] = err;
totalError += err;
}
n = m_tree->GetSuccessor(n);
}
return totalError;
}
void Jacobian::UpdatedSClampValue(VectorR3* targets)
{
// Traverse tree to find all end effectors
VectorR3 temp;
Node* n = m_tree->GetRoot();
while (n)
{
if (n->IsEffector())
{
int i = n->GetEffectorNum();
const VectorR3& targetPos = targets[i];
// Compute the delta S value (differences from end effectors to target positions.
// While we are at it, also update the clamping values in dSclamp;
temp = targetPos;
temp -= n->GetS();
double normSi = sqrt(Square(dS[i]) + Square(dS[i + 1]) + Square(dS[i + 2]));
double changedDist = temp.Norm() - normSi;
if (changedDist > 0.0)
{
dSclamp[i] = BaseMaxTargetDist + changedDist;
}
else
{
dSclamp[i] = BaseMaxTargetDist;
}
}
n = m_tree->GetSuccessor(n);
}
}
void Jacobian::CompareErrors(const Jacobian& j1, const Jacobian& j2, double* weightedDist1, double* weightedDist2)
{
const VectorRn& e1 = j1.errorArray;
const VectorRn& e2 = j2.errorArray;
double ret1 = 0.0;
double ret2 = 0.0;
int len = e1.GetLength();
for (long i = 0; i < len; i++)
{
double v1 = e1[i];
double v2 = e2[i];
if (v1 < v2)
{
ret1 += v1 / v2;
ret2 += 1.0;
}
else if (v1 != 0.0)
{
ret1 += 1.0;
ret2 += v2 / v1;
}
else
{
ret1 += 0.0;
ret2 += 0.0;
}
}
*weightedDist1 = ret1;
*weightedDist2 = ret2;
}
void Jacobian::CountErrors(const Jacobian& j1, const Jacobian& j2, int* numBetter1, int* numBetter2, int* numTies)
{
const VectorRn& e1 = j1.errorArray;
const VectorRn& e2 = j2.errorArray;
int b1 = 0, b2 = 0, tie = 0;
int len = e1.GetLength();
for (long i = 0; i < len; i++)
{
double v1 = e1[i];
double v2 = e2[i];
if (v1 < v2)
{
b1++;
}
else if (v2 < v1)
{
b2++;
}
else
{
tie++;
}
}
*numBetter1 = b1;
*numBetter2 = b2;
*numTies = tie;
}
/* THIS VERSION IS NOT AS GOOD. DO NOT USE!
void Jacobian::CalcDeltaThetasSDLSrev2()
{
const MatrixRmn& J = ActiveJacobian();
// Compute Singular Value Decomposition
J.ComputeSVD( U, w, V );
// Next line for debugging only
assert(J.DebugCheckSVD(U, w , V));
// Calculate response vector dTheta that is the SDLS solution.
// Delta target values are the dS values
int nRows = J.GetNumRows();
int numEndEffectors = tree->GetNumEffector(); // Equals the number of rows of J divided by three
int nCols = J.GetNumColumns();
dTheta.SetZero();
// Calculate the norms of the 3-vectors in the Jacobian
long i;
const double *jx = J.GetPtr();
double *jnx = Jnorms.GetPtr();
for ( i=nCols*numEndEffectors; i>0; i-- ) {
double accumSq = Square(*(jx++));
accumSq += Square(*(jx++));
accumSq += Square(*(jx++));
*(jnx++) = sqrt(accumSq);
}
// Loop over each singular vector
for ( i=0; i<nRows; i++ ) {
double wiInv = w[i];
if ( NearZero(wiInv,1.0e-10) ) {
continue;
}
double N = 0.0; // N is the quasi-1-norm of the i-th column of U
double alpha = 0.0; // alpha is the dot product of dS and the i-th column of U
const double *dSx = dS.GetPtr();
const double *ux = U.GetColumnPtr(i);
long j;
for ( j=numEndEffectors; j>0; j-- ) {
double tmp;
alpha += (*ux)*(*(dSx++));
tmp = Square( *(ux++) );
alpha += (*ux)*(*(dSx++));
tmp += Square(*(ux++));
alpha += (*ux)*(*(dSx++));
tmp += Square(*(ux++));
N += sqrt(tmp);
}
// P is the quasi-1-norm of the response to angles changing according to the i-th column of V
double P = 0.0;
double *vx = V.GetColumnPtr(i);
jnx = Jnorms.GetPtr();
for ( j=nCols; j>0; j-- ) {
double accum=0.0;
for ( long k=numEndEffectors; k>0; k-- ) {
accum += *(jnx++);
}
P += fabs((*(vx++)))*accum;
}
double lambda = 1.0;
if ( N<P ) {
lambda -= N/P; // Scale back maximum permissable joint angle
}
lambda *= lambda;
lambda *= DampingLambdaSDLS;
// Calculate the dTheta from pure pseudoinverse considerations
double scale = alpha*wiInv/(Square(wiInv)+Square(lambda)); // This times i-th column of V is the SDLS response
MatrixRmn::AddArrayScale(nCols, V.GetColumnPtr(i), 1, dTheta.GetPtr(), 1, scale );
}
// Scale back to not exceed maximum angle changes
double maxChange = dTheta.MaxAbs();
if ( maxChange>MaxAngleSDLS ) {
dTheta *= MaxAngleSDLS/maxChange;
}
} */

View file

@ -0,0 +1,146 @@
/*
*
* Inverse Kinematics software, with several solvers including
* Selectively Damped Least Squares Method
* Damped Least Squares Method
* Pure Pseudoinverse Method
* Jacobian Transpose Method
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/index.html
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include "Node.h"
#include "Tree.h"
#include "MathMisc.h"
#include "LinearR3.h"
#include "VectorRn.h"
#include "MatrixRmn.h"
#ifndef _CLASS_JACOBIAN
#define _CLASS_JACOBIAN
#ifdef _DYNAMIC
const double BASEMAXDIST = 0.02;
#else
const double MAXDIST = 0.08; // optimal value for double Y shape : 0.08
#endif
const double DELTA = 0.4;
const long double LAMBDA = 2.0; // only for DLS. optimal : 0.24
const double NEARZERO = 0.0000000001;
enum UpdateMode
{
JACOB_Undefined = 0,
JACOB_JacobianTranspose = 1,
JACOB_PseudoInverse = 2,
JACOB_DLS = 3,
JACOB_SDLS = 4
};
class Jacobian
{
public:
Jacobian(Tree*);
Jacobian(bool useAngularJacobian, int nDof, int numEndEffectors);
void ComputeJacobian(VectorR3* targets);
const MatrixRmn& ActiveJacobian() const { return *Jactive; }
void SetJendActive() { Jactive = &Jend; } // The default setting is Jend.
void SetJtargetActive() { Jactive = &Jtarget; }
void SetJendTrans(MatrixRmn& J);
void SetDeltaS(VectorRn& S);
void CalcDeltaThetas(MatrixRmn& AugMat); // Use this only if the Current Mode has been set.
void ZeroDeltaThetas();
void CalcDeltaThetasTranspose();
void CalcDeltaThetasPseudoinverse();
void CalcDeltaThetasDLS(MatrixRmn& AugMat);
void CalcDeltaThetasDLS2(const VectorRn& dVec, MatrixRmn& AugMat);
void CalcDeltaThetasDLSwithSVD();
void CalcDeltaThetasSDLS();
void CalcDeltaThetasDLSwithNullspace(const VectorRn& desiredV, MatrixRmn& AugMat);
void UpdateThetas();
void UpdateThetaDot();
double UpdateErrorArray(VectorR3* targets); // Returns sum of errors
const VectorRn& GetErrorArray() const { return errorArray; }
void UpdatedSClampValue(VectorR3* targets);
void SetCurrentMode(UpdateMode mode) { CurrentUpdateMode = mode; }
UpdateMode GetCurrentMode() const { return CurrentUpdateMode; }
void SetDampingDLS(double lambda)
{
DampingLambda = lambda;
DampingLambdaSq = Square(lambda);
}
void Reset();
static void CompareErrors(const Jacobian& j1, const Jacobian& j2, double* weightedDist1, double* weightedDist2);
static void CountErrors(const Jacobian& j1, const Jacobian& j2, int* numBetter1, int* numBetter2, int* numTies);
int GetNumRows() { return nRow; }
int GetNumCols() { return nCol; }
public:
Tree* m_tree; // tree associated with this Jacobian matrix
int m_nEffector; // Number of end effectors
int nJoint; // Number of joints
int nRow; // Total number of rows the real J (= 3*number of end effectors for now)
int nCol; // Total number of columns in the real J (= number of joints for now)
MatrixRmn Jend; // Jacobian matrix based on end effector positions
MatrixRmn Jtarget; // Jacobian matrix based on target positions
MatrixRmn Jnorms; // Norms of 3-vectors in active Jacobian (SDLS only)
MatrixRmn U; // J = U * Diag(w) * V^T (Singular Value Decomposition)
VectorRn w;
MatrixRmn V;
UpdateMode CurrentUpdateMode;
VectorRn dS; // delta s
VectorRn dT1; // delta t -- these are delta S values clamped to smaller magnitude
VectorRn dSclamp; // Value to clamp magnitude of dT at.
VectorRn dTheta; // delta theta
VectorRn dPreTheta; // delta theta for single eigenvalue (SDLS only)
VectorRn errorArray; // Distance of end effectors from target after updating
// Parameters for pseudoinverses
static const double PseudoInverseThresholdFactor; // Threshold for treating eigenvalue as zero (fraction of largest eigenvalue)
// Parameters for damped least squares
static const double DefaultDampingLambda;
double DampingLambda;
double DampingLambdaSq;
//double DampingLambdaSDLS;
// Cap on max. value of changes in angles in single update step
static const double MaxAngleJtranspose;
static const double MaxAnglePseudoinverse;
static const double MaxAngleDLS;
static const double MaxAngleSDLS;
MatrixRmn* Jactive;
void CalcdTClampedFromdS();
static const double BaseMaxTargetDist;
};
#endif

View file

@ -0,0 +1,12 @@
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/index.html
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View file

@ -0,0 +1,89 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include "LinearR2.h"
#include <assert.h>
// ******************************************************
// * VectorR2 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
const VectorR2 VectorR2::Zero(0.0, 0.0);
const VectorR2 VectorR2::UnitX(1.0, 0.0);
const VectorR2 VectorR2::UnitY(0.0, 1.0);
const VectorR2 VectorR2::NegUnitX(-1.0, 0.0);
const VectorR2 VectorR2::NegUnitY(0.0, -1.0);
const Matrix2x2 Matrix2x2::Identity(1.0, 0.0, 0.0, 1.0);
// ******************************************************
// * Matrix2x2 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
// ******************************************************
// * LinearMapR2 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
LinearMapR2 LinearMapR2::Inverse() const // Returns inverse
{
double detInv = 1.0 / (m11 * m22 - m12 * m21);
return (LinearMapR2(m22 * detInv, -m21 * detInv, -m12 * detInv, m11 * detInv));
}
LinearMapR2& LinearMapR2::Invert() // Converts into inverse.
{
double detInv = 1.0 / (m11 * m22 - m12 * m21);
double temp;
temp = m11 * detInv;
m11 = m22 * detInv;
m22 = temp;
m12 = -m12 * detInv;
m21 = -m22 * detInv;
return (*this);
}
VectorR2 LinearMapR2::Solve(const VectorR2& u) const // Returns solution
{
// Just uses Inverse() for now.
return (Inverse() * u);
}
// ******************************************************
// * RotationMapR2 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
// ***************************************************************
// * 2-space vector and matrix utilities *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// ***************************************************************
// Stream Output Routines *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ostream& operator<<(ostream& os, const VectorR2& u)
{
return (os << "<" << u.x << "," << u.y << ">");
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,831 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include "MathMisc.h"
#include "LinearR3.h"
#include "Spherical.h"
// ******************************************************
// * VectorR3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
const VectorR3 UnitVecIR3(1.0, 0.0, 0.0);
const VectorR3 UnitVecJR3(0.0, 1.0, 0.0);
const VectorR3 UnitVecKR3(0.0, 0.0, 1.0);
const VectorR3 VectorR3::Zero(0.0, 0.0, 0.0);
const VectorR3 VectorR3::UnitX(1.0, 0.0, 0.0);
const VectorR3 VectorR3::UnitY(0.0, 1.0, 0.0);
const VectorR3 VectorR3::UnitZ(0.0, 0.0, 1.0);
const VectorR3 VectorR3::NegUnitX(-1.0, 0.0, 0.0);
const VectorR3 VectorR3::NegUnitY(0.0, -1.0, 0.0);
const VectorR3 VectorR3::NegUnitZ(0.0, 0.0, -1.0);
const Matrix3x3 Matrix3x3::Identity(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
const Matrix3x4 Matrix3x4::Identity(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
double VectorR3::MaxAbs() const
{
double m;
m = (x > 0.0) ? x : -x;
if (y > m)
m = y;
else if (-y > m)
m = -y;
if (z > m)
m = z;
else if (-z > m)
m = -z;
return m;
}
VectorR3& VectorR3::Set(const Quaternion& q)
{
double sinhalf = sqrt(Square(q.x) + Square(q.y) + Square(q.z));
if (sinhalf > 0.0)
{
double theta = atan2(sinhalf, q.w);
theta += theta;
this->Set(q.x, q.y, q.z);
(*this) *= (theta / sinhalf);
}
else
{
this->SetZero();
}
return *this;
}
// *********************************************************************
// Rotation routines *
// *********************************************************************
// s.Rotate(theta, u) rotates s and returns s
// rotated theta degrees around unit vector w.
VectorR3& VectorR3::Rotate(double theta, const VectorR3& w)
{
double c = cos(theta);
double s = sin(theta);
double dotw = (x * w.x + y * w.y + z * w.z);
double v0x = dotw * w.x;
double v0y = dotw * w.y; // v0 = provjection onto w
double v0z = dotw * w.z;
double v1x = x - v0x;
double v1y = y - v0y; // v1 = projection onto plane normal to w
double v1z = z - v0z;
double v2x = w.y * v1z - w.z * v1y;
double v2y = w.z * v1x - w.x * v1z; // v2 = w * v1 (cross product)
double v2z = w.x * v1y - w.y * v1x;
x = v0x + c * v1x + s * v2x;
y = v0y + c * v1y + s * v2y;
z = v0z + c * v1z + s * v2z;
return (*this);
}
// Rotate unit vector x in the direction of "dir": length of dir is rotation angle.
// x must be a unit vector. dir must be perpindicular to x.
VectorR3& VectorR3::RotateUnitInDirection(const VectorR3& dir)
{
double theta = dir.NormSq();
if (theta == 0.0)
{
return *this;
}
else
{
theta = sqrt(theta);
double costheta = cos(theta);
double sintheta = sin(theta);
VectorR3 dirUnit = dir / theta;
*this = costheta * (*this) + sintheta * dirUnit;
return (*this);
}
}
// ******************************************************
// * Matrix3x3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
Matrix3x3& Matrix3x3::ReNormalize() // Re-normalizes nearly orthonormal matrix
{
double alpha = m11 * m11 + m21 * m21 + m31 * m31; // First column's norm squared
double beta = m12 * m12 + m22 * m22 + m32 * m32; // Second column's norm squared
double gamma = m13 * m13 + m23 * m23 + m33 * m33; // Third column's norm squared
alpha = 1.0 - 0.5 * (alpha - 1.0); // Get mult. factor
beta = 1.0 - 0.5 * (beta - 1.0);
gamma = 1.0 - 0.5 * (gamma - 1.0);
m11 *= alpha; // Renormalize first column
m21 *= alpha;
m31 *= alpha;
m12 *= beta; // Renormalize second column
m22 *= beta;
m32 *= beta;
m13 *= gamma;
m23 *= gamma;
m33 *= gamma;
alpha = m11 * m12 + m21 * m22 + m31 * m32; // First and second column dot product
beta = m11 * m13 + m21 * m23 + m31 * m33; // First and third column dot product
gamma = m12 * m13 + m22 * m23 + m32 * m33; // Second and third column dot product
alpha *= 0.5;
beta *= 0.5;
gamma *= 0.5;
double temp1, temp2;
temp1 = m11 - alpha * m12 - beta * m13; // Update row1
temp2 = m12 - alpha * m11 - gamma * m13;
m13 -= beta * m11 + gamma * m12;
m11 = temp1;
m12 = temp2;
temp1 = m21 - alpha * m22 - beta * m23; // Update row2
temp2 = m22 - alpha * m21 - gamma * m23;
m23 -= beta * m21 + gamma * m22;
m21 = temp1;
m22 = temp2;
temp1 = m31 - alpha * m32 - beta * m33; // Update row3
temp2 = m32 - alpha * m31 - gamma * m33;
m33 -= beta * m31 + gamma * m32;
m31 = temp1;
m32 = temp2;
return *this;
}
void Matrix3x3::OperatorTimesEquals(const Matrix3x3& B) // Matrix product
{
double t1, t2; // temporary values
t1 = m11 * B.m11 + m12 * B.m21 + m13 * B.m31;
t2 = m11 * B.m12 + m12 * B.m22 + m13 * B.m32;
m13 = m11 * B.m13 + m12 * B.m23 + m13 * B.m33;
m11 = t1;
m12 = t2;
t1 = m21 * B.m11 + m22 * B.m21 + m23 * B.m31;
t2 = m21 * B.m12 + m22 * B.m22 + m23 * B.m32;
m23 = m21 * B.m13 + m22 * B.m23 + m23 * B.m33;
m21 = t1;
m22 = t2;
t1 = m31 * B.m11 + m32 * B.m21 + m33 * B.m31;
t2 = m31 * B.m12 + m32 * B.m22 + m33 * B.m32;
m33 = m31 * B.m13 + m32 * B.m23 + m33 * B.m33;
m31 = t1;
m32 = t2;
return;
}
VectorR3 Matrix3x3::Solve(const VectorR3& u) const // Returns solution
{ // based on Cramer's rule
double sd11 = m22 * m33 - m23 * m32;
double sd21 = m32 * m13 - m12 * m33;
double sd31 = m12 * m23 - m22 * m13;
double sd12 = m31 * m23 - m21 * m33;
double sd22 = m11 * m33 - m31 * m13;
double sd32 = m21 * m13 - m11 * m23;
double sd13 = m21 * m32 - m31 * m22;
double sd23 = m31 * m12 - m11 * m32;
double sd33 = m11 * m22 - m21 * m12;
double detInv = 1.0 / (m11 * sd11 + m12 * sd12 + m13 * sd13);
double rx = (u.x * sd11 + u.y * sd21 + u.z * sd31) * detInv;
double ry = (u.x * sd12 + u.y * sd22 + u.z * sd32) * detInv;
double rz = (u.x * sd13 + u.y * sd23 + u.z * sd33) * detInv;
return (VectorR3(rx, ry, rz));
}
// ******************************************************
// * Matrix3x4 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
Matrix3x4& Matrix3x4::ReNormalize() // Re-normalizes nearly orthonormal matrix
{
double alpha = m11 * m11 + m21 * m21 + m31 * m31; // First column's norm squared
double beta = m12 * m12 + m22 * m22 + m32 * m32; // Second column's norm squared
double gamma = m13 * m13 + m23 * m23 + m33 * m33; // Third column's norm squared
alpha = 1.0 - 0.5 * (alpha - 1.0); // Get mult. factor
beta = 1.0 - 0.5 * (beta - 1.0);
gamma = 1.0 - 0.5 * (gamma - 1.0);
m11 *= alpha; // Renormalize first column
m21 *= alpha;
m31 *= alpha;
m12 *= beta; // Renormalize second column
m22 *= beta;
m32 *= beta;
m13 *= gamma;
m23 *= gamma;
m33 *= gamma;
alpha = m11 * m12 + m21 * m22 + m31 * m32; // First and second column dot product
beta = m11 * m13 + m21 * m23 + m31 * m33; // First and third column dot product
gamma = m12 * m13 + m22 * m23 + m32 * m33; // Second and third column dot product
alpha *= 0.5;
beta *= 0.5;
gamma *= 0.5;
double temp1, temp2;
temp1 = m11 - alpha * m12 - beta * m13; // Update row1
temp2 = m12 - alpha * m11 - gamma * m13;
m13 -= beta * m11 + gamma * m12;
m11 = temp1;
m12 = temp2;
temp1 = m21 - alpha * m22 - beta * m23; // Update row2
temp2 = m22 - alpha * m21 - gamma * m23;
m23 -= beta * m21 + gamma * m22;
m21 = temp1;
m22 = temp2;
temp1 = m31 - alpha * m32 - beta * m33; // Update row3
temp2 = m32 - alpha * m31 - gamma * m33;
m33 -= beta * m31 + gamma * m32;
m31 = temp1;
m32 = temp2;
return *this;
}
void Matrix3x4::OperatorTimesEquals(const Matrix3x4& B) // Composition
{
m14 += m11 * B.m14 + m12 * B.m24 + m13 * B.m34;
m24 += m21 * B.m14 + m22 * B.m24 + m23 * B.m34;
m34 += m31 * B.m14 + m32 * B.m24 + m33 * B.m34;
double t1, t2; // temporary values
t1 = m11 * B.m11 + m12 * B.m21 + m13 * B.m31;
t2 = m11 * B.m12 + m12 * B.m22 + m13 * B.m32;
m13 = m11 * B.m13 + m12 * B.m23 + m13 * B.m33;
m11 = t1;
m12 = t2;
t1 = m21 * B.m11 + m22 * B.m21 + m23 * B.m31;
t2 = m21 * B.m12 + m22 * B.m22 + m23 * B.m32;
m23 = m21 * B.m13 + m22 * B.m23 + m23 * B.m33;
m21 = t1;
m22 = t2;
t1 = m31 * B.m11 + m32 * B.m21 + m33 * B.m31;
t2 = m31 * B.m12 + m32 * B.m22 + m33 * B.m32;
m33 = m31 * B.m13 + m32 * B.m23 + m33 * B.m33;
m31 = t1;
m32 = t2;
}
void Matrix3x4::OperatorTimesEquals(const Matrix3x3& B) // Composition
{
double t1, t2; // temporary values
t1 = m11 * B.m11 + m12 * B.m21 + m13 * B.m31;
t2 = m11 * B.m12 + m12 * B.m22 + m13 * B.m32;
m13 = m11 * B.m13 + m12 * B.m23 + m13 * B.m33;
m11 = t1;
m12 = t2;
t1 = m21 * B.m11 + m22 * B.m21 + m23 * B.m31;
t2 = m21 * B.m12 + m22 * B.m22 + m23 * B.m32;
m23 = m21 * B.m13 + m22 * B.m23 + m23 * B.m33;
m21 = t1;
m22 = t2;
t1 = m31 * B.m11 + m32 * B.m21 + m33 * B.m31;
t2 = m31 * B.m12 + m32 * B.m22 + m33 * B.m32;
m33 = m31 * B.m13 + m32 * B.m23 + m33 * B.m33;
m31 = t1;
m32 = t2;
}
// ******************************************************
// * LinearMapR3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
LinearMapR3 operator*(const LinearMapR3& A, const LinearMapR3& B)
{
return (LinearMapR3(A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31,
A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31,
A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31,
A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32,
A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32,
A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32,
A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33,
A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33,
A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33));
}
double LinearMapR3::Determinant() const // Returns the determinant
{
return (m11 * (m22 * m33 - m23 * m32) - m12 * (m21 * m33 - m31 * m23) + m13 * (m21 * m23 - m31 * m22));
}
LinearMapR3 LinearMapR3::Inverse() const // Returns inverse
{
double sd11 = m22 * m33 - m23 * m32;
double sd21 = m32 * m13 - m12 * m33;
double sd31 = m12 * m23 - m22 * m13;
double sd12 = m31 * m23 - m21 * m33;
double sd22 = m11 * m33 - m31 * m13;
double sd32 = m21 * m13 - m11 * m23;
double sd13 = m21 * m32 - m31 * m22;
double sd23 = m31 * m12 - m11 * m32;
double sd33 = m11 * m22 - m21 * m12;
double detInv = 1.0 / (m11 * sd11 + m12 * sd12 + m13 * sd13);
return (LinearMapR3(sd11 * detInv, sd12 * detInv, sd13 * detInv,
sd21 * detInv, sd22 * detInv, sd23 * detInv,
sd31 * detInv, sd32 * detInv, sd33 * detInv));
}
LinearMapR3& LinearMapR3::Invert() // Converts into inverse.
{
double sd11 = m22 * m33 - m23 * m32;
double sd21 = m32 * m13 - m12 * m33;
double sd31 = m12 * m23 - m22 * m13;
double sd12 = m31 * m23 - m21 * m33;
double sd22 = m11 * m33 - m31 * m13;
double sd32 = m21 * m13 - m11 * m23;
double sd13 = m21 * m32 - m31 * m22;
double sd23 = m31 * m12 - m11 * m32;
double sd33 = m11 * m22 - m21 * m12;
double detInv = 1.0 / (m11 * sd11 + m12 * sd12 + m13 * sd13);
m11 = sd11 * detInv;
m12 = sd21 * detInv;
m13 = sd31 * detInv;
m21 = sd12 * detInv;
m22 = sd22 * detInv;
m23 = sd32 * detInv;
m31 = sd13 * detInv;
m32 = sd23 * detInv;
m33 = sd33 * detInv;
return (*this);
}
// ******************************************************
// * AffineMapR3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
AffineMapR3 operator*(const AffineMapR3& A, const AffineMapR3& B)
{
return (AffineMapR3(A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31,
A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31,
A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31,
A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32,
A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32,
A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32,
A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33,
A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33,
A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33,
A.m11 * B.m14 + A.m12 * B.m24 + A.m13 * B.m34 + A.m14,
A.m21 * B.m14 + A.m22 * B.m24 + A.m23 * B.m34 + A.m24,
A.m31 * B.m14 + A.m32 * B.m24 + A.m33 * B.m34 + A.m34));
}
AffineMapR3 operator*(const LinearMapR3& A, const AffineMapR3& B)
{
return (AffineMapR3(A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31,
A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31,
A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31,
A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32,
A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32,
A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32,
A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33,
A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33,
A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33,
A.m11 * B.m14 + A.m12 * B.m24 + A.m13 * B.m34,
A.m21 * B.m14 + A.m22 * B.m24 + A.m23 * B.m34,
A.m31 * B.m14 + A.m32 * B.m24 + A.m33 * B.m34));
}
AffineMapR3 operator*(const AffineMapR3& A, const LinearMapR3& B)
{
return (AffineMapR3(A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31,
A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31,
A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31,
A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32,
A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32,
A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32,
A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33,
A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33,
A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33,
A.m14,
A.m24,
A.m34));
}
AffineMapR3 AffineMapR3::Inverse() const // Returns inverse
{
double sd11 = m22 * m33 - m23 * m32;
double sd21 = m32 * m13 - m12 * m33;
double sd31 = m12 * m23 - m22 * m13;
double sd12 = m31 * m23 - m21 * m33;
double sd22 = m11 * m33 - m31 * m13;
double sd32 = m21 * m13 - m11 * m23;
double sd13 = m21 * m32 - m31 * m22;
double sd23 = m31 * m12 - m11 * m32;
double sd33 = m11 * m22 - m21 * m12;
double detInv = 1.0 / (m11 * sd11 + m12 * sd12 + m13 * sd13);
// Make sd's hold the (transpose of) the inverse of the 3x3 part
sd11 *= detInv;
sd12 *= detInv;
sd13 *= detInv;
sd21 *= detInv;
sd22 *= detInv;
sd23 *= detInv;
sd31 *= detInv;
sd32 *= detInv;
sd33 *= detInv;
double sd41 = -(m14 * sd11 + m24 * sd21 + m34 * sd31);
double sd42 = -(m14 * sd12 + m24 * sd22 + m34 * sd32);
double sd43 = -(m14 * sd12 + m24 * sd23 + m34 * sd33);
return (AffineMapR3(sd11, sd12, sd13,
sd21, sd22, sd23,
sd31, sd32, sd33,
sd41, sd42, sd43));
}
AffineMapR3& AffineMapR3::Invert() // Converts into inverse.
{
double sd11 = m22 * m33 - m23 * m32;
double sd21 = m32 * m13 - m12 * m33;
double sd31 = m12 * m23 - m22 * m13;
double sd12 = m31 * m23 - m21 * m33;
double sd22 = m11 * m33 - m31 * m13;
double sd32 = m21 * m13 - m11 * m23;
double sd13 = m21 * m32 - m31 * m22;
double sd23 = m31 * m12 - m11 * m32;
double sd33 = m11 * m22 - m21 * m12;
double detInv = 1.0 / (m11 * sd11 + m12 * sd12 + m13 * sd13);
m11 = sd11 * detInv;
m12 = sd21 * detInv;
m13 = sd31 * detInv;
m21 = sd12 * detInv;
m22 = sd22 * detInv;
m23 = sd32 * detInv;
m31 = sd13 * detInv;
m32 = sd23 * detInv;
m33 = sd33 * detInv;
double sd41 = -(m14 * m11 + m24 * m12 + m34 * m13); // Compare to ::Inverse.
double sd42 = -(m14 * m21 + m24 * m22 + m34 * m23);
double sd43 = -(m14 * m31 + m24 * m32 + m34 * m33);
m14 = sd41;
m24 = sd42;
m34 = sd43;
return (*this);
}
// **************************************************************
// * RotationMapR3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **
RotationMapR3 operator*(const RotationMapR3& A, const RotationMapR3& B)
// Matrix product (composition)
{
return (RotationMapR3(A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31,
A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31,
A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31,
A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32,
A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32,
A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32,
A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33,
A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33,
A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33));
}
RotationMapR3& RotationMapR3::Set(const Quaternion& quat)
{
double wSq = quat.w * quat.w;
double xSq = quat.x * quat.x;
double ySq = quat.y * quat.y;
double zSq = quat.z * quat.z;
double Dqwx = 2.0 * quat.w * quat.x;
double Dqwy = 2.0 * quat.w * quat.y;
double Dqwz = 2.0 * quat.w * quat.z;
double Dqxy = 2.0 * quat.x * quat.y;
double Dqyz = 2.0 * quat.y * quat.z;
double Dqxz = 2.0 * quat.x * quat.z;
m11 = wSq + xSq - ySq - zSq;
m22 = wSq - xSq + ySq - zSq;
m33 = wSq - xSq - ySq + zSq;
m12 = Dqxy - Dqwz;
m21 = Dqxy + Dqwz;
m13 = Dqxz + Dqwy;
m31 = Dqxz - Dqwy;
m23 = Dqyz - Dqwx;
m32 = Dqyz + Dqwx;
return *this;
}
RotationMapR3& RotationMapR3::Set(const VectorR3& u, double theta)
{
assert(fabs(u.NormSq() - 1.0) < 2.0e-6);
double c = cos(theta);
double s = sin(theta);
double mc = 1.0 - c;
double xmc = u.x * mc;
double xymc = xmc * u.y;
double xzmc = xmc * u.z;
double yzmc = u.y * u.z * mc;
double xs = u.x * s;
double ys = u.y * s;
double zs = u.z * s;
Matrix3x3::Set(u.x * u.x * mc + c, xymc + zs, xzmc - ys,
xymc - zs, u.y * u.y * mc + c, yzmc + xs,
xzmc + ys, yzmc - xs, u.z * u.z * mc + c);
return *this;
}
// The rotation axis vector u MUST be a UNIT vector!!!
RotationMapR3& RotationMapR3::Set(const VectorR3& u, double s, double c)
{
assert(fabs(u.NormSq() - 1.0) < 2.0e-6);
double mc = 1.0 - c;
double xmc = u.x * mc;
double xymc = xmc * u.y;
double xzmc = xmc * u.z;
double yzmc = u.y * u.z * mc;
double xs = u.x * s;
double ys = u.y * s;
double zs = u.z * s;
Matrix3x3::Set(u.x * u.x * mc + c, xymc + zs, xzmc - ys,
xymc - zs, u.y * u.y * mc + c, yzmc + xs,
xzmc + ys, yzmc - xs, u.z * u.z * mc + c);
return *this;
}
// ToAxisAndAngle - find a unit vector in the direction of the rotation axis,
// and the angle theta of rotation. Returns true if the rotation angle is non-zero,
// and false if it is zero.
bool RotationMapR3::ToAxisAndAngle(VectorR3* u, double* theta) const
{
double alpha = m11 + m22 + m33 - 1.0;
double beta = sqrt(Square(m32 - m23) + Square(m13 - m31) + Square(m21 - m12));
if (beta == 0.0)
{
*u = VectorR3::UnitY;
*theta = 0.0;
return false;
}
else
{
u->Set(m32 - m23, m13 - m31, m21 - m12);
*u /= beta;
*theta = atan2(beta, alpha);
return true;
}
}
// VrRotate is similar to glRotate. Returns a matrix (LinearMapR3)
// that will perform the rotation when multiplied on the left.
// u is supposed to be a *unit* vector. Otherwise, the LinearMapR3
// returned will be garbage!
RotationMapR3 VrRotate(double theta, const VectorR3& u)
{
RotationMapR3 ret;
ret.Set(u, theta);
return ret;
}
// This version of rotate takes the cosine and sine of theta
// instead of theta. u must still be a unit vector.
RotationMapR3 VrRotate(double c, double s, const VectorR3& u)
{
RotationMapR3 ret;
ret.Set(u, s, c);
return ret;
}
// Returns a RotationMapR3 which rotates the fromVec to be colinear
// with toVec.
RotationMapR3 VrRotateAlign(const VectorR3& fromVec, const VectorR3& toVec)
{
VectorR3 crossVec = fromVec;
crossVec *= toVec;
double sinetheta = crossVec.Norm(); // Not yet normalized!
if (sinetheta < 1.0e-40)
{
return (RotationMapR3(
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0));
}
crossVec /= sinetheta; // Normalize the vector
double scale = 1.0 / sqrt(fromVec.NormSq() * toVec.NormSq());
sinetheta *= scale;
double cosinetheta = (fromVec ^ toVec) * scale;
return (VrRotate(cosinetheta, sinetheta, crossVec));
}
// RotateToMap returns a rotation map which rotates fromVec to have the
// same direction as toVec.
// fromVec and toVec should be unit vectors
RotationMapR3 RotateToMap(const VectorR3& fromVec, const VectorR3& toVec)
{
VectorR3 crossVec = fromVec;
crossVec *= toVec;
double sintheta = crossVec.Norm();
double costheta = fromVec ^ toVec;
if (sintheta <= 1.0e-40)
{
if (costheta > 0.0)
{
return (RotationMapR3(
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0));
}
else
{
GetOrtho(toVec, crossVec); // Get arbitrary orthonormal vector
return (VrRotate(costheta, sintheta, crossVec));
}
}
else
{
crossVec /= sintheta; // Normalize the vector
return (VrRotate(costheta, sintheta, crossVec));
}
}
// **************************************************************
// * RigidMapR3 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **
// The rotation axis vector u MUST be a UNIT vector!!!
RigidMapR3& RigidMapR3::SetRotationPart(const VectorR3& u, double theta)
{
assert(fabs(u.NormSq() - 1.0) < 2.0e-6);
double c = cos(theta);
double s = sin(theta);
double mc = 1.0 - c;
double xmc = u.x * mc;
double xymc = xmc * u.y;
double xzmc = xmc * u.z;
double yzmc = u.y * u.z * mc;
double xs = u.x * s;
double ys = u.y * s;
double zs = u.z * s;
Matrix3x4::Set3x3(u.x * u.x * mc + c, xymc + zs, xzmc - ys,
xymc - zs, u.y * u.y * mc + c, yzmc + xs,
xzmc + ys, yzmc - xs, u.z * u.z * mc + c);
return *this;
}
// The rotation axis vector u MUST be a UNIT vector!!!
RigidMapR3& RigidMapR3::SetRotationPart(const VectorR3& u, double s, double c)
{
assert(fabs(u.NormSq() - 1.0) < 2.0e-6);
double mc = 1.0 - c;
double xmc = u.x * mc;
double xymc = xmc * u.y;
double xzmc = xmc * u.z;
double yzmc = u.y * u.z * mc;
double xs = u.x * s;
double ys = u.y * s;
double zs = u.z * s;
Matrix3x4::Set3x3(u.x * u.x * mc + c, xymc + zs, xzmc - ys,
xymc - zs, u.y * u.y * mc + c, yzmc + xs,
xzmc + ys, yzmc - xs, u.z * u.z * mc + c);
return *this;
}
// CalcGlideRotation - converts a rigid map into an equivalent
// glide rotation (screw motion). It returns the rotation axis
// as base point u, and a rotation axis v. The vectors u and v are
// always orthonormal. v will be a unit vector.
// It also returns the glide distance, which is the translation parallel
// to v. Further, it returns the signed rotation angle theta (right hand rule
// specifies the direction.
// The glide rotation means a rotation around the point u with axis direction v.
// Return code "true" if the rotation amount is non-zero. "false" if pure translation.
bool RigidMapR3::CalcGlideRotation(VectorR3* u, VectorR3* v,
double* glideDist, double* rotation) const
{
// Compare to the code for ToAxisAndAngle.
double alpha = m11 + m22 + m33 - 1.0;
double beta = sqrt(Square(m32 - m23) + Square(m13 - m31) + Square(m21 - m12));
if (beta == 0.0)
{
double vN = m14 * m14 + m24 * m24 + m34 * m34;
if (vN > 0.0)
{
vN = sqrt(vN);
v->Set(m14, m24, m34);
*v /= vN;
*glideDist = vN;
}
else
{
*v = VectorR3::UnitX;
*glideDist = 0.0;
}
u->SetZero();
*rotation = 0;
return false;
}
else
{
v->Set(m32 - m23, m13 - m31, m21 - m12);
*v /= beta; // v - unit vector, rotation axis
*rotation = atan2(beta, alpha);
u->Set(m14, m24, m34);
*glideDist = ((*u) ^ (*v));
VectorR3 temp = *v;
temp *= *glideDist;
*u -= temp; // Subtract component in direction of rot. axis v
temp = *v;
temp *= *u;
temp /= tan((*rotation) / 2); // temp = (v \times u) / tan(rotation/2)
*u += temp;
*u *= 0.5;
return true;
}
}
// ***************************************************************
// Linear Algebra Utilities *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Returns a righthanded orthonormal basis to complement vector u
void GetOrtho(const VectorR3& u, VectorR3& v, VectorR3& w)
{
if (u.x > 0.5 || u.x < -0.5 || u.y > 0.5 || u.y < -0.5)
{
v.Set(u.y, -u.x, 0.0);
}
else
{
v.Set(0.0, u.z, -u.y);
}
v.Normalize();
w = u;
w *= v;
w.Normalize();
// w.NormalizeFast();
return;
}
// Returns a vector v orthonormal to unit vector u
void GetOrtho(const VectorR3& u, VectorR3& v)
{
if (u.x > 0.5 || u.x < -0.5 || u.y > 0.5 || u.y < -0.5)
{
v.Set(u.y, -u.x, 0.0);
}
else
{
v.Set(0.0, u.z, -u.y);
}
v.Normalize();
return;
}
// ***************************************************************
// Stream Output Routines *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ostream& operator<<(ostream& os, const VectorR3& u)
{
return (os << "<" << u.x << "," << u.y << "," << u.z << ">");
}
ostream& operator<<(ostream& os, const Matrix3x3& A)
{
os << " <" << A.m11 << ", " << A.m12 << ", " << A.m13 << ">\n"
<< " <" << A.m21 << ", " << A.m22 << ", " << A.m23 << ">\n"
<< " <" << A.m31 << ", " << A.m32 << ", " << A.m33 << ">\n";
return (os);
}
ostream& operator<<(ostream& os, const Matrix3x4& A)
{
os << " <" << A.m11 << ", " << A.m12 << ", " << A.m13
<< "; " << A.m14 << ">\n"
<< " <" << A.m21 << ", " << A.m22 << ", " << A.m23
<< "; " << A.m24 << ">\n"
<< " <" << A.m31 << ", " << A.m32 << ", " << A.m33
<< "; " << A.m34 << ">\n";
return (os);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,467 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include "LinearR4.h"
#include <assert.h>
const VectorR4 VectorR4::Zero(0.0, 0.0, 0.0, 0.0);
const VectorR4 VectorR4::UnitX(1.0, 0.0, 0.0, 0.0);
const VectorR4 VectorR4::UnitY(0.0, 1.0, 0.0, 0.0);
const VectorR4 VectorR4::UnitZ(0.0, 0.0, 1.0, 0.0);
const VectorR4 VectorR4::UnitW(0.0, 0.0, 0.0, 1.0);
const VectorR4 VectorR4::NegUnitX(-1.0, 0.0, 0.0, 0.0);
const VectorR4 VectorR4::NegUnitY(0.0, -1.0, 0.0, 0.0);
const VectorR4 VectorR4::NegUnitZ(0.0, 0.0, -1.0, 0.0);
const VectorR4 VectorR4::NegUnitW(0.0, 0.0, 0.0, -1.0);
const Matrix4x4 Matrix4x4::Identity(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// ******************************************************
// * VectorR4 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
double VectorR4::MaxAbs() const
{
double m;
m = (x > 0.0) ? x : -x;
if (y > m)
m = y;
else if (-y > m)
m = -y;
if (z > m)
m = z;
else if (-z > m)
m = -z;
if (w > m)
m = w;
else if (-w > m)
m = -w;
return m;
}
// ******************************************************
// * Matrix4x4 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
void Matrix4x4::operator*=(const Matrix4x4& B) // Matrix product
{
double t1, t2, t3; // temporary values
t1 = m11 * B.m11 + m12 * B.m21 + m13 * B.m31 + m14 * B.m41;
t2 = m11 * B.m12 + m12 * B.m22 + m13 * B.m32 + m14 * B.m42;
t3 = m11 * B.m13 + m12 * B.m23 + m13 * B.m33 + m14 * B.m43;
m14 = m11 * B.m14 + m12 * B.m24 + m13 * B.m34 + m14 * B.m44;
m11 = t1;
m12 = t2;
m13 = t3;
t1 = m21 * B.m11 + m22 * B.m21 + m23 * B.m31 + m24 * B.m41;
t2 = m21 * B.m12 + m22 * B.m22 + m23 * B.m32 + m24 * B.m42;
t3 = m21 * B.m13 + m22 * B.m23 + m23 * B.m33 + m24 * B.m43;
m24 = m21 * B.m14 + m22 * B.m24 + m23 * B.m34 + m24 * B.m44;
m21 = t1;
m22 = t2;
m23 = t3;
t1 = m31 * B.m11 + m32 * B.m21 + m33 * B.m31 + m34 * B.m41;
t2 = m31 * B.m12 + m32 * B.m22 + m33 * B.m32 + m34 * B.m42;
t3 = m31 * B.m13 + m32 * B.m23 + m33 * B.m33 + m34 * B.m43;
m34 = m31 * B.m14 + m32 * B.m24 + m33 * B.m34 + m34 * B.m44;
m31 = t1;
m32 = t2;
m33 = t3;
t1 = m41 * B.m11 + m42 * B.m21 + m43 * B.m31 + m44 * B.m41;
t2 = m41 * B.m12 + m42 * B.m22 + m43 * B.m32 + m44 * B.m42;
t3 = m41 * B.m13 + m42 * B.m23 + m43 * B.m33 + m44 * B.m43;
m44 = m41 * B.m14 + m42 * B.m24 + m43 * B.m34 + m44 * B.m44;
m41 = t1;
m42 = t2;
m43 = t3;
}
inline void ReNormalizeHelper(double& a, double& b, double& c, double& d)
{
double scaleF = a * a + b * b + c * c + d * d; // Inner product of Vector-R4
scaleF = 1.0 - 0.5 * (scaleF - 1.0);
a *= scaleF;
b *= scaleF;
c *= scaleF;
d *= scaleF;
}
Matrix4x4& Matrix4x4::ReNormalize()
{
ReNormalizeHelper(m11, m21, m31, m41); // Renormalize first column
ReNormalizeHelper(m12, m22, m32, m42); // Renormalize second column
ReNormalizeHelper(m13, m23, m33, m43); // Renormalize third column
ReNormalizeHelper(m14, m24, m34, m44); // Renormalize fourth column
double alpha = 0.5 * (m11 * m12 + m21 * m22 + m31 * m32 + m41 * m42); //1st and 2nd cols
double beta = 0.5 * (m11 * m13 + m21 * m23 + m31 * m33 + m41 * m43); //1st and 3rd cols
double gamma = 0.5 * (m11 * m14 + m21 * m24 + m31 * m34 + m41 * m44); //1st and 4nd cols
double delta = 0.5 * (m12 * m13 + m22 * m23 + m32 * m33 + m42 * m43); //2nd and 3rd cols
double eps = 0.5 * (m12 * m14 + m22 * m24 + m32 * m34 + m42 * m44); //2nd and 4nd cols
double phi = 0.5 * (m13 * m14 + m23 * m24 + m33 * m34 + m43 * m44); //3rd and 4nd cols
double temp1, temp2, temp3;
temp1 = m11 - alpha * m12 - beta * m13 - gamma * m14;
temp2 = m12 - alpha * m11 - delta * m13 - eps * m14;
temp3 = m13 - beta * m11 - delta * m12 - phi * m14;
m14 -= (gamma * m11 + eps * m12 + phi * m13);
m11 = temp1;
m12 = temp2;
m13 = temp3;
temp1 = m21 - alpha * m22 - beta * m23 - gamma * m24;
temp2 = m22 - alpha * m21 - delta * m23 - eps * m24;
temp3 = m23 - beta * m21 - delta * m22 - phi * m24;
m24 -= (gamma * m21 + eps * m22 + phi * m23);
m21 = temp1;
m22 = temp2;
m23 = temp3;
temp1 = m31 - alpha * m32 - beta * m33 - gamma * m34;
temp2 = m32 - alpha * m31 - delta * m33 - eps * m34;
temp3 = m33 - beta * m31 - delta * m32 - phi * m34;
m34 -= (gamma * m31 + eps * m32 + phi * m33);
m31 = temp1;
m32 = temp2;
m33 = temp3;
temp1 = m41 - alpha * m42 - beta * m43 - gamma * m44;
temp2 = m42 - alpha * m41 - delta * m43 - eps * m44;
temp3 = m43 - beta * m41 - delta * m42 - phi * m44;
m44 -= (gamma * m41 + eps * m42 + phi * m43);
m41 = temp1;
m42 = temp2;
m43 = temp3;
return *this;
}
// ******************************************************
// * LinearMapR4 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
double LinearMapR4::Determinant() const // Returns the determinant
{
double Tbt34C12 = m31 * m42 - m32 * m41; // 2x2 subdeterminants
double Tbt34C13 = m31 * m43 - m33 * m41;
double Tbt34C14 = m31 * m44 - m34 * m41;
double Tbt34C23 = m32 * m43 - m33 * m42;
double Tbt34C24 = m32 * m44 - m34 * m42;
double Tbt34C34 = m33 * m44 - m34 * m43;
double sd11 = m22 * Tbt34C34 - m23 * Tbt34C24 + m24 * Tbt34C23; // 3x3 subdeterminants
double sd12 = m21 * Tbt34C34 - m23 * Tbt34C14 + m24 * Tbt34C13;
double sd13 = m21 * Tbt34C24 - m22 * Tbt34C14 + m24 * Tbt34C12;
double sd14 = m21 * Tbt34C23 - m22 * Tbt34C13 + m23 * Tbt34C12;
return (m11 * sd11 - m12 * sd12 + m13 * sd13 - m14 * sd14);
}
LinearMapR4 LinearMapR4::Inverse() const // Returns inverse
{
double Tbt34C12 = m31 * m42 - m32 * m41; // 2x2 subdeterminants
double Tbt34C13 = m31 * m43 - m33 * m41;
double Tbt34C14 = m31 * m44 - m34 * m41;
double Tbt34C23 = m32 * m43 - m33 * m42;
double Tbt34C24 = m32 * m44 - m34 * m42;
double Tbt34C34 = m33 * m44 - m34 * m43;
double Tbt24C12 = m21 * m42 - m22 * m41; // 2x2 subdeterminants
double Tbt24C13 = m21 * m43 - m23 * m41;
double Tbt24C14 = m21 * m44 - m24 * m41;
double Tbt24C23 = m22 * m43 - m23 * m42;
double Tbt24C24 = m22 * m44 - m24 * m42;
double Tbt24C34 = m23 * m44 - m24 * m43;
double Tbt23C12 = m21 * m32 - m22 * m31; // 2x2 subdeterminants
double Tbt23C13 = m21 * m33 - m23 * m31;
double Tbt23C14 = m21 * m34 - m24 * m31;
double Tbt23C23 = m22 * m33 - m23 * m32;
double Tbt23C24 = m22 * m34 - m24 * m32;
double Tbt23C34 = m23 * m34 - m24 * m33;
double sd11 = m22 * Tbt34C34 - m23 * Tbt34C24 + m24 * Tbt34C23; // 3x3 subdeterminants
double sd12 = m21 * Tbt34C34 - m23 * Tbt34C14 + m24 * Tbt34C13;
double sd13 = m21 * Tbt34C24 - m22 * Tbt34C14 + m24 * Tbt34C12;
double sd14 = m21 * Tbt34C23 - m22 * Tbt34C13 + m23 * Tbt34C12;
double sd21 = m12 * Tbt34C34 - m13 * Tbt34C24 + m14 * Tbt34C23; // 3x3 subdeterminants
double sd22 = m11 * Tbt34C34 - m13 * Tbt34C14 + m14 * Tbt34C13;
double sd23 = m11 * Tbt34C24 - m12 * Tbt34C14 + m14 * Tbt34C12;
double sd24 = m11 * Tbt34C23 - m12 * Tbt34C13 + m13 * Tbt34C12;
double sd31 = m12 * Tbt24C34 - m13 * Tbt24C24 + m14 * Tbt24C23; // 3x3 subdeterminants
double sd32 = m11 * Tbt24C34 - m13 * Tbt24C14 + m14 * Tbt24C13;
double sd33 = m11 * Tbt24C24 - m12 * Tbt24C14 + m14 * Tbt24C12;
double sd34 = m11 * Tbt24C23 - m12 * Tbt24C13 + m13 * Tbt24C12;
double sd41 = m12 * Tbt23C34 - m13 * Tbt23C24 + m14 * Tbt23C23; // 3x3 subdeterminants
double sd42 = m11 * Tbt23C34 - m13 * Tbt23C14 + m14 * Tbt23C13;
double sd43 = m11 * Tbt23C24 - m12 * Tbt23C14 + m14 * Tbt23C12;
double sd44 = m11 * Tbt23C23 - m12 * Tbt23C13 + m13 * Tbt23C12;
double detInv = 1.0 / (m11 * sd11 - m12 * sd12 + m13 * sd13 - m14 * sd14);
return (LinearMapR4(sd11 * detInv, -sd12 * detInv, sd13 * detInv, -sd14 * detInv,
-sd21 * detInv, sd22 * detInv, -sd23 * detInv, sd24 * detInv,
sd31 * detInv, -sd32 * detInv, sd33 * detInv, -sd34 * detInv,
-sd41 * detInv, sd42 * detInv, -sd43 * detInv, sd44 * detInv));
}
LinearMapR4& LinearMapR4::Invert() // Converts into inverse.
{
double Tbt34C12 = m31 * m42 - m32 * m41; // 2x2 subdeterminants
double Tbt34C13 = m31 * m43 - m33 * m41;
double Tbt34C14 = m31 * m44 - m34 * m41;
double Tbt34C23 = m32 * m43 - m33 * m42;
double Tbt34C24 = m32 * m44 - m34 * m42;
double Tbt34C34 = m33 * m44 - m34 * m43;
double Tbt24C12 = m21 * m42 - m22 * m41; // 2x2 subdeterminants
double Tbt24C13 = m21 * m43 - m23 * m41;
double Tbt24C14 = m21 * m44 - m24 * m41;
double Tbt24C23 = m22 * m43 - m23 * m42;
double Tbt24C24 = m22 * m44 - m24 * m42;
double Tbt24C34 = m23 * m44 - m24 * m43;
double Tbt23C12 = m21 * m32 - m22 * m31; // 2x2 subdeterminants
double Tbt23C13 = m21 * m33 - m23 * m31;
double Tbt23C14 = m21 * m34 - m24 * m31;
double Tbt23C23 = m22 * m33 - m23 * m32;
double Tbt23C24 = m22 * m34 - m24 * m32;
double Tbt23C34 = m23 * m34 - m24 * m33;
double sd11 = m22 * Tbt34C34 - m23 * Tbt34C24 + m24 * Tbt34C23; // 3x3 subdeterminants
double sd12 = m21 * Tbt34C34 - m23 * Tbt34C14 + m24 * Tbt34C13;
double sd13 = m21 * Tbt34C24 - m22 * Tbt34C14 + m24 * Tbt34C12;
double sd14 = m21 * Tbt34C23 - m22 * Tbt34C13 + m23 * Tbt34C12;
double sd21 = m12 * Tbt34C34 - m13 * Tbt34C24 + m14 * Tbt34C23; // 3x3 subdeterminants
double sd22 = m11 * Tbt34C34 - m13 * Tbt34C14 + m14 * Tbt34C13;
double sd23 = m11 * Tbt34C24 - m12 * Tbt34C14 + m14 * Tbt34C12;
double sd24 = m11 * Tbt34C23 - m12 * Tbt34C13 + m13 * Tbt34C12;
double sd31 = m12 * Tbt24C34 - m13 * Tbt24C24 + m14 * Tbt24C23; // 3x3 subdeterminants
double sd32 = m11 * Tbt24C34 - m13 * Tbt24C14 + m14 * Tbt24C13;
double sd33 = m11 * Tbt24C24 - m12 * Tbt24C14 + m14 * Tbt24C12;
double sd34 = m11 * Tbt24C23 - m12 * Tbt24C13 + m13 * Tbt24C12;
double sd41 = m12 * Tbt23C34 - m13 * Tbt23C24 + m14 * Tbt23C23; // 3x3 subdeterminants
double sd42 = m11 * Tbt23C34 - m13 * Tbt23C14 + m14 * Tbt23C13;
double sd43 = m11 * Tbt23C24 - m12 * Tbt23C14 + m14 * Tbt23C12;
double sd44 = m11 * Tbt23C23 - m12 * Tbt23C13 + m13 * Tbt23C12;
double detInv = 1.0 / (m11 * sd11 - m12 * sd12 + m13 * sd13 - m14 * sd14);
m11 = sd11 * detInv;
m12 = -sd21 * detInv;
m13 = sd31 * detInv;
m14 = -sd41 * detInv;
m21 = -sd12 * detInv;
m22 = sd22 * detInv;
m23 = -sd32 * detInv;
m24 = sd42 * detInv;
m31 = sd13 * detInv;
m32 = -sd23 * detInv;
m33 = sd33 * detInv;
m34 = -sd43 * detInv;
m41 = -sd14 * detInv;
m42 = sd24 * detInv;
m43 = -sd34 * detInv;
m44 = sd44 * detInv;
return (*this);
}
VectorR4 LinearMapR4::Solve(const VectorR4& u) const // Returns solution
{
// Just uses Inverse() for now.
return (Inverse() * u);
}
// ******************************************************
// * RotationMapR4 class - math library functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * **
// ***************************************************************
// * 4-space vector and matrix utilities *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Returns u * v^T
LinearMapR4 TimesTranspose(const VectorR4& u, const VectorR4& v)
{
LinearMapR4 result;
TimesTranspose(u, v, result);
return result;
}
// The following routines are use to obtain
// a righthanded orthonormal basis to complement vectors u,v,w.
// The vectors u,v,w must be unit and orthonormal.
// The value is returned in "rotmat" with the first column(s) of
// rotmat equal to u,v,w as appropriate.
void GetOrtho(const VectorR4& u, RotationMapR4& rotmat)
{
rotmat.SetColumn1(u);
GetOrtho(1, rotmat);
}
void GetOrtho(const VectorR4& u, const VectorR4& v, RotationMapR4& rotmat)
{
rotmat.SetColumn1(u);
rotmat.SetColumn2(v);
GetOrtho(2, rotmat);
}
void GetOrtho(const VectorR4& u, const VectorR4& v, const VectorR4& s,
RotationMapR4& rotmat)
{
rotmat.SetColumn1(u);
rotmat.SetColumn2(v);
rotmat.SetColumn3(s);
GetOrtho(3, rotmat);
}
// This final version of GetOrtho is mainly for internal use.
// It uses a Gram-Schmidt procedure to extend a partial orthonormal
// basis to a complete orthonormal basis.
// j = number of columns of rotmat that have already been set.
void GetOrtho(int j, RotationMapR4& rotmat)
{
if (j == 0)
{
rotmat.SetIdentity();
return;
}
if (j == 1)
{
rotmat.SetColumn2(-rotmat.m21, rotmat.m11, -rotmat.m41, rotmat.m31);
j = 2;
}
assert(rotmat.Column1().Norm() < 1.0001 && 0.9999 < rotmat.Column1().Norm() && rotmat.Column1().Norm() < 1.0001 && 0.9999 < rotmat.Column1().Norm() && (rotmat.Column1() ^ rotmat.Column2()) < 0.001 && (rotmat.Column1() ^ rotmat.Column2()) > -0.001);
// 2x2 subdeterminants in first 2 columns
double d12 = rotmat.m11 * rotmat.m22 - rotmat.m12 * rotmat.m21;
double d13 = rotmat.m11 * rotmat.m32 - rotmat.m12 * rotmat.m31;
double d14 = rotmat.m11 * rotmat.m42 - rotmat.m12 * rotmat.m41;
double d23 = rotmat.m21 * rotmat.m32 - rotmat.m22 * rotmat.m31;
double d24 = rotmat.m21 * rotmat.m42 - rotmat.m22 * rotmat.m41;
double d34 = rotmat.m31 * rotmat.m42 - rotmat.m32 * rotmat.m41;
VectorR4 vec3;
if (j == 2)
{
if (d12 > 0.4 || d12 < -0.4 || d13 > 0.4 || d13 < -0.4 || d23 > 0.4 || d23 < -0.4)
{
vec3.Set(d23, -d13, d12, 0.0);
}
else if (d24 > 0.4 || d24 < -0.4 || d14 > 0.4 || d14 < -0.4)
{
vec3.Set(d24, -d14, 0.0, d12);
}
else
{
vec3.Set(d34, 0.0, -d14, d13);
}
vec3.Normalize();
rotmat.SetColumn3(vec3);
}
// Do the final column
rotmat.SetColumn4(
-rotmat.m23 * d34 + rotmat.m33 * d24 - rotmat.m43 * d23,
rotmat.m13 * d34 - rotmat.m33 * d14 + rotmat.m43 * d13,
-rotmat.m13 * d24 + rotmat.m23 * d14 - rotmat.m43 * d12,
rotmat.m13 * d23 - rotmat.m23 * d13 + rotmat.m33 * d12);
assert(0.99 < (((LinearMapR4)rotmat)).Determinant() && (((LinearMapR4)rotmat)).Determinant() < 1.01);
}
// *********************************************************************
// Rotation routines *
// *********************************************************************
// Rotate unit vector x in the direction of "dir": length of dir is rotation angle.
// x must be a unit vector. dir must be perpindicular to x.
VectorR4& VectorR4::RotateUnitInDirection(const VectorR4& dir)
{
assert(this->Norm() < 1.0001 && this->Norm() > 0.9999 &&
(dir ^ (*this)) < 0.0001 && (dir ^ (*this)) > -0.0001);
double theta = dir.NormSq();
if (theta == 0.0)
{
return *this;
}
else
{
theta = sqrt(theta);
double costheta = cos(theta);
double sintheta = sin(theta);
VectorR4 dirUnit = dir / theta;
*this = costheta * (*this) + sintheta * dirUnit;
// this->NormalizeFast();
return (*this);
}
}
// RotateToMap returns a RotationMapR4 that rotates fromVec to toVec,
// leaving the orthogonal subspace fixed.
// fromVec and toVec should be unit vectors
RotationMapR4 RotateToMap(const VectorR4& fromVec, const VectorR4& toVec)
{
LinearMapR4 result;
result.SetIdentity();
LinearMapR4 temp;
VectorR4 vPerp = ProjectPerpUnitDiff(toVec, fromVec);
double sintheta = vPerp.Norm(); // theta = angle between toVec and fromVec
VectorR4 vProj = toVec - vPerp;
double costheta = vProj ^ fromVec;
if (sintheta == 0.0)
{
// The vectors either coincide (return identity) or directly oppose
if (costheta < 0.0)
{
result = -result; // Vectors directly oppose: return -identity.
}
}
else
{
vPerp /= sintheta; // Normalize
VectorProjectMap(fromVec, temp); // project in fromVec direction
temp *= (costheta - 1.0);
result += temp;
VectorProjectMap(vPerp, temp); // Project in vPerp direction
temp *= (costheta - 1.0);
result += temp;
TimesTranspose(vPerp, fromVec, temp); // temp = (vPerp)*(fromVec^T)
temp *= sintheta;
result += temp;
temp.MakeTranspose();
result -= temp; // (-sintheta)*(fromVec)*(vPerp^T)
}
RotationMapR4 rotationResult;
rotationResult.Set(result); // Make explicitly a RotationMapR4
return rotationResult;
}
// ***************************************************************
// Stream Output Routines *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ostream& operator<<(ostream& os, const VectorR4& u)
{
return (os << "<" << u.x << "," << u.y << "," << u.z << "," << u.w << ">");
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,447 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#ifndef MATH_MISC_H
#define MATH_MISC_H
#include <math.h>
//
// Commonly used constants
//
const double PI = 3.1415926535897932384626433832795028841972;
const double PI2 = 2.0 * PI;
const double PI4 = 4.0 * PI;
const double PISq = PI * PI;
const double PIhalves = 0.5 * PI;
const double PIthirds = PI / 3.0;
const double PItwothirds = PI2 / 3.0;
const double PIfourths = 0.25 * PI;
const double PIsixths = PI / 6.0;
const double PIsixthsSq = PIsixths * PIsixths;
const double PItwelfths = PI / 12.0;
const double PItwelfthsSq = PItwelfths * PItwelfths;
const double PIinv = 1.0 / PI;
const double PI2inv = 0.5 / PI;
const double PIhalfinv = 2.0 / PI;
const double RadiansToDegrees = 180.0 / PI;
const double DegreesToRadians = PI / 180;
const double OneThird = 1.0 / 3.0;
const double TwoThirds = 2.0 / 3.0;
const double OneSixth = 1.0 / 6.0;
const double OneEighth = 1.0 / 8.0;
const double OneTwelfth = 1.0 / 12.0;
const double Root2 = sqrt(2.0);
const double Root3 = sqrt(3.0);
const double Root2Inv = 1.0 / Root2; // sqrt(2)/2
const double HalfRoot3 = sqrtf(3) / 2.0;
const double LnTwo = log(2.0);
const double LnTwoInv = 1.0 / log(2.0);
// Special purpose constants
const double OnePlusEpsilon15 = 1.0 + 1.0e-15;
const double OneMinusEpsilon15 = 1.0 - 1.0e-15;
inline double ZeroValue(const double& x)
{
return 0.0;
}
//
// Comparisons
//
template <class T>
inline T Min(T x, T y)
{
return (x < y ? x : y);
}
template <class T>
inline T Max(T x, T y)
{
return (y < x ? x : y);
}
template <class T>
inline T ClampRange(T x, T min, T max)
{
if (x < min)
{
return min;
}
if (x > max)
{
return max;
}
return x;
}
template <class T>
inline bool ClampRange(T* x, T min, T max)
{
if ((*x) < min)
{
(*x) = min;
return false;
}
else if ((*x) > max)
{
(*x) = max;
return false;
}
else
{
return true;
}
}
template <class T>
inline bool ClampMin(T* x, T min)
{
if ((*x) < min)
{
(*x) = min;
return false;
}
return true;
}
template <class T>
inline bool ClampMax(T* x, T max)
{
if ((*x) > max)
{
(*x) = max;
return false;
}
return true;
}
template <class T>
inline T& UpdateMin(const T& x, T& y)
{
if (x < y)
{
y = x;
}
return y;
}
template <class T>
inline T& UpdateMax(const T& x, T& y)
{
if (x > y)
{
y = x;
}
return y;
}
template <class T>
inline bool SameSignNonzero(T x, T y)
{
if (x < 0)
{
return (y < 0);
}
else if (0 < x)
{
return (0 < y);
}
else
{
return false;
}
}
inline double Mag(double x)
{
return fabs(x);
}
inline double Dist(double x, double y)
{
return fabs(x - y);
}
template <class T>
inline bool NearEqual(T a, T b, double tolerance)
{
a -= b;
return (Mag(a) <= tolerance);
}
inline bool EqualZeroFuzzy(double x)
{
return (fabs(x) <= 1.0e-14);
}
inline bool NearZero(double x, double tolerance)
{
return (fabs(x) <= tolerance);
}
inline bool LessOrEqualFuzzy(double x, double y)
{
if (x <= y)
{
return true;
}
if (y > 0.0)
{
if (x > 0.0)
{
return (x * OneMinusEpsilon15 < y * OnePlusEpsilon15);
}
else
{
return (y < 1.0e-15); // x==0 in this case
}
}
else if (y < 0.0)
{
if (x < 0.0)
{
return (x * OnePlusEpsilon15 < y * OneMinusEpsilon15);
}
else
{
return (y > -1.0e-15); // x==0 in this case
}
}
else
{
return (-1.0e-15 < x && x < 1.0e-15);
}
}
inline bool GreaterOrEqualFuzzy(double x, double y)
{
return LessOrEqualFuzzy(y, x);
}
inline bool UpdateMaxAbs(double* maxabs, double updateval)
{
if (updateval > *maxabs)
{
*maxabs = updateval;
return true;
}
else if (-updateval > *maxabs)
{
*maxabs = -updateval;
return true;
}
else
{
return false;
}
}
// **********************************************************
// Combinations and averages. *
// **********************************************************
template <class T>
void averageOf(const T& a, const T& b, T& c)
{
c = a;
c += b;
c *= 0.5;
}
template <class T>
void Lerp(const T& a, const T& b, double alpha, T& c)
{
double beta = 1.0 - alpha;
if (beta > alpha)
{
c = b;
c *= alpha / beta;
c += a;
c *= beta;
}
else
{
c = a;
c *= beta / alpha;
c += b;
c *= alpha;
}
}
template <class T>
T Lerp(const T& a, const T& b, double alpha)
{
T ret;
Lerp(a, b, alpha, ret);
return ret;
}
// **********************************************************
// Trigonometry *
// **********************************************************
// TimesCot(x) returns x*cot(x)
inline double TimesCot(double x)
{
if (-1.0e-5 < x && x < 1.0e-5)
{
return 1.0 + x * OneThird;
}
else
{
return (x * cos(x) / sin(x));
}
}
// SineOver(x) returns sin(x)/x.
inline double SineOver(double x)
{
if (-1.0e-5 < x && x < 1.0e-5)
{
return 1.0 - x * x * OneSixth;
}
else
{
return sin(x) / x;
}
}
// OverSine(x) returns x/sin(x).
inline double OverSine(double x)
{
if (-1.0e-5 < x && x < 1.0e-5)
{
return 1.0 + x * x * OneSixth;
}
else
{
return x / sin(x);
}
}
inline double SafeAsin(double x)
{
if (x <= -1.0)
{
return -PIhalves;
}
else if (x >= 1.0)
{
return PIhalves;
}
else
{
return asin(x);
}
}
inline double SafeAcos(double x)
{
if (x <= -1.0)
{
return PI;
}
else if (x >= 1.0)
{
return 0.0;
}
else
{
return acos(x);
}
}
// **********************************************************************
// Roots and powers *
// **********************************************************************
// Square(x) returns x*x, of course!
template <class T>
inline T Square(T x)
{
return (x * x);
}
// Cube(x) returns x*x*x, of course!
template <class T>
inline T Cube(T x)
{
return (x * x * x);
}
// SafeSqrt(x) = returns sqrt(max(x, 0.0));
inline double SafeSqrt(double x)
{
if (x <= 0.0)
{
return 0.0;
}
else
{
return sqrt(x);
}
}
// SignedSqrt(a, s) returns (sign(s)*sqrt(a)).
inline double SignedSqrt(double a, double sgn)
{
if (sgn == 0.0)
{
return 0.0;
}
else
{
return (sgn > 0.0 ? sqrt(a) : -sqrt(a));
}
}
// Template version of Sign function
template <class T>
inline int Sign(T x)
{
if (x < 0)
{
return -1;
}
else if (x == 0)
{
return 0;
}
else
{
return 1;
}
}
#endif // #ifndef MATH_MISC_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,417 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
//
// MatrixRmn: Matrix over reals (Variable dimensional vector)
//
// Not very sophisticated yet. Needs more functionality
// To do: better handling of resizing.
//
#ifndef MATRIX_RMN_H
#define MATRIX_RMN_H
#include <math.h>
#include <assert.h>
#include "LinearR3.h"
#include "VectorRn.h"
class MatrixRmn
{
public:
MatrixRmn(); // Null constructor
MatrixRmn(long numRows, long numCols); // Constructor with length
~MatrixRmn(); // Destructor
void SetSize(long numRows, long numCols);
long GetNumRows() const { return NumRows; }
long GetNumColumns() const { return NumCols; }
void SetZero();
// Return entry in row i and column j.
double Get(long i, long j) const;
void GetTriple(long i, long j, VectorR3* retValue) const;
// Use GetPtr to get pointer into the array (efficient)
// Is friendly in that anyone can change the array contents (be careful!)
// The entries are in column order!!!
// Use this with care. You may call GetRowStride and GetColStride to navigate
// within the matrix. I do not expect these values to ever change.
const double* GetPtr() const;
double* GetPtr();
const double* GetPtr(long i, long j) const;
double* GetPtr(long i, long j);
const double* GetColumnPtr(long j) const;
double* GetColumnPtr(long j);
const double* GetRowPtr(long i) const;
double* GetRowPtr(long i);
long GetRowStride() const { return NumRows; } // Step size (stride) along a row
long GetColStride() const { return 1; } // Step size (stide) along a column
void Set(long i, long j, double val);
void SetTriple(long i, long c, const VectorR3& u);
void SetIdentity();
void SetDiagonalEntries(double d);
void SetDiagonalEntries(const VectorRn& d);
void SetSuperDiagonalEntries(double d);
void SetSuperDiagonalEntries(const VectorRn& d);
void SetSubDiagonalEntries(double d);
void SetSubDiagonalEntries(const VectorRn& d);
void SetColumn(long i, const VectorRn& d);
void SetRow(long i, const VectorRn& d);
void SetSequence(const VectorRn& d, long startRow, long startCol, long deltaRow, long deltaCol);
// Loads matrix in as a sub-matrix. (i,j) is the base point. Defaults to (0,0).
// The "Tranpose" versions load the transpose of A.
void LoadAsSubmatrix(const MatrixRmn& A);
void LoadAsSubmatrix(long i, long j, const MatrixRmn& A);
void LoadAsSubmatrixTranspose(const MatrixRmn& A);
void LoadAsSubmatrixTranspose(long i, long j, const MatrixRmn& A);
// Norms
double FrobeniusNormSq() const;
double FrobeniusNorm() const;
// Operations on VectorRn's
void Multiply(const VectorRn& v, VectorRn& result) const; // result = (this)*(v)
void MultiplyTranspose(const VectorRn& v, VectorRn& result) const; // Equivalent to mult by row vector on left
double DotProductColumn(const VectorRn& v, long colNum) const; // Returns dot product of v with i-th column
// Operations on MatrixRmn's
MatrixRmn& operator*=(double);
MatrixRmn& operator/=(double d)
{
assert(d != 0.0);
*this *= (1.0 / d);
return *this;
}
MatrixRmn& AddScaled(const MatrixRmn& B, double factor);
MatrixRmn& operator+=(const MatrixRmn& B);
MatrixRmn& operator-=(const MatrixRmn& B);
static MatrixRmn& Multiply(const MatrixRmn& A, const MatrixRmn& B, MatrixRmn& dst); // Sets dst = A*B.
static MatrixRmn& MultiplyTranspose(const MatrixRmn& A, const MatrixRmn& B, MatrixRmn& dst); // Sets dst = A*(B-tranpose).
static MatrixRmn& TransposeMultiply(const MatrixRmn& A, const MatrixRmn& B, MatrixRmn& dst); // Sets dst = (A-transpose)*B.
// Miscellaneous operation
MatrixRmn& AddToDiagonal(double d); // Adds d to each diagonal
MatrixRmn& AddToDiagonal(const VectorRn& dVec);
// Solving systems of linear equations
void Solve(const VectorRn& b, VectorRn* x, MatrixRmn& AugMat) const; // Solves the equation (*this)*x = b; Uses row operations. Assumes *this is invertible.
// Row Echelon Form and Reduced Row Echelon Form routines
// Row echelon form here allows non-negative entries (instead of 1's) in the positions of lead variables.
void ConvertToRefNoFree(); // Converts the matrix in place to row echelon form -- assumption is no free variables will be found
void ConvertToRef(int numVars); // Converts the matrix in place to row echelon form -- numVars is number of columns to work with.
void ConvertToRef(int numVars, double eps); // Same, but eps is the measure of closeness to zero
// Givens transformation
static void CalcGivensValues(double a, double b, double* c, double* s);
void PostApplyGivens(double c, double s, long idx); // Applies Givens transform to columns idx and idx+1.
void PostApplyGivens(double c, double s, long idx1, long idx2); // Applies Givens transform to columns idx1 and idx2.
// Singular value decomposition
void ComputeSVD(MatrixRmn& U, VectorRn& w, MatrixRmn& V) const;
// Good for debugging SVD computations (I recommend this be used for any new application to check for bugs/instability).
bool DebugCheckSVD(const MatrixRmn& U, const VectorRn& w, const MatrixRmn& V) const;
// Compute inverse of a matrix, the result is written in R
void ComputeInverse(MatrixRmn& R) const;
// Debug matrix inverse computation
bool DebugCheckInverse(const MatrixRmn& MInv) const;
// Some useful routines for experts who understand the inner workings of these classes.
inline static double DotArray(long length, const double* ptrA, long strideA, const double* ptrB, long strideB);
inline static void CopyArrayScale(long length, const double* from, long fromStride, double* to, long toStride, double scale);
inline static void AddArrayScale(long length, const double* from, long fromStride, double* to, long toStride, double scale);
private:
long NumRows; // Number of rows
long NumCols; // Number of columns
double* x; // Array of vector entries - stored in column order
long AllocSize; // Allocated size of the x array
// Internal helper routines for SVD calculations
static void CalcBidiagonal(MatrixRmn& U, MatrixRmn& V, VectorRn& w, VectorRn& superDiag);
void ConvertBidiagToDiagonal(MatrixRmn& U, MatrixRmn& V, VectorRn& w, VectorRn& superDiag) const;
static void SvdHouseholder(double* basePt,
long colLength, long numCols, long colStride, long rowStride,
double* retFirstEntry);
void ExpandHouseholders(long numXforms, int numZerosSkipped, const double* basePt, long colStride, long rowStride);
static bool UpdateBidiagIndices(long* firstDiagIdx, long* lastBidiagIdx, VectorRn& w, VectorRn& superDiag, double eps);
static void ApplyGivensCBTD(double cosine, double sine, double* a, double* b, double* c, double* d);
static void ApplyGivensCBTD(double cosine, double sine, double* a, double* b, double* c,
double d, double* e, double* f);
static void ClearRowWithDiagonalZero(long firstBidiagIdx, long lastBidiagIdx,
MatrixRmn& U, double* wPtr, double* sdPtr, double eps);
static void ClearColumnWithDiagonalZero(long endIdx, MatrixRmn& V, double* wPtr, double* sdPtr, double eps);
bool DebugCalcBidiagCheck(const MatrixRmn& U, const VectorRn& w, const VectorRn& superDiag, const MatrixRmn& V) const;
};
inline MatrixRmn::MatrixRmn()
{
NumRows = 0;
NumCols = 0;
x = 0;
AllocSize = 0;
}
inline MatrixRmn::MatrixRmn(long numRows, long numCols)
{
NumRows = 0;
NumCols = 0;
x = 0;
AllocSize = 0;
SetSize(numRows, numCols);
}
inline MatrixRmn::~MatrixRmn()
{
delete[] x;
}
// Resize.
// If the array space is decreased, the information about the allocated length is lost.
inline void MatrixRmn::SetSize(long numRows, long numCols)
{
assert(numRows > 0 && numCols > 0);
long newLength = numRows * numCols;
if (newLength > AllocSize)
{
delete[] x;
AllocSize = Max(newLength, AllocSize << 1);
x = new double[AllocSize];
}
NumRows = numRows;
NumCols = numCols;
}
// Zero out the entire vector
inline void MatrixRmn::SetZero()
{
double* target = x;
for (long i = NumRows * NumCols; i > 0; i--)
{
*(target++) = 0.0;
}
}
// Return entry in row i and column j.
inline double MatrixRmn::Get(long i, long j) const
{
assert(i < NumRows && j < NumCols);
return *(x + j * NumRows + i);
}
// Return a VectorR3 out of a column. Starts at row 3*i, in column j.
inline void MatrixRmn::GetTriple(long i, long j, VectorR3* retValue) const
{
long ii = 3 * i;
assert(0 <= i && ii + 2 < NumRows && 0 <= j && j < NumCols);
retValue->Load(x + j * NumRows + ii);
}
// Get a pointer to the (0,0) entry.
// The entries are in column order.
// This version gives read-only pointer
inline const double* MatrixRmn::GetPtr() const
{
return x;
}
// Get a pointer to the (0,0) entry.
// The entries are in column order.
inline double* MatrixRmn::GetPtr()
{
return x;
}
// Get a pointer to the (i,j) entry.
// The entries are in column order.
// This version gives read-only pointer
inline const double* MatrixRmn::GetPtr(long i, long j) const
{
assert(0 <= i && i < NumRows && 0 <= j && j < NumCols);
return (x + j * NumRows + i);
}
// Get a pointer to the (i,j) entry.
// The entries are in column order.
// This version gives pointer to writable data
inline double* MatrixRmn::GetPtr(long i, long j)
{
assert(i < NumRows && j < NumCols);
return (x + j * NumRows + i);
}
// Get a pointer to the j-th column.
// The entries are in column order.
// This version gives read-only pointer
inline const double* MatrixRmn::GetColumnPtr(long j) const
{
assert(0 <= j && j < NumCols);
return (x + j * NumRows);
}
// Get a pointer to the j-th column.
// This version gives pointer to writable data
inline double* MatrixRmn::GetColumnPtr(long j)
{
assert(0 <= j && j < NumCols);
return (x + j * NumRows);
}
/// Get a pointer to the i-th row
// The entries are in column order.
// This version gives read-only pointer
inline const double* MatrixRmn::GetRowPtr(long i) const
{
assert(0 <= i && i < NumRows);
return (x + i);
}
// Get a pointer to the i-th row
// This version gives pointer to writable data
inline double* MatrixRmn::GetRowPtr(long i)
{
assert(0 <= i && i < NumRows);
return (x + i);
}
// Set the (i,j) entry of the matrix
inline void MatrixRmn::Set(long i, long j, double val)
{
assert(i < NumRows && j < NumCols);
*(x + j * NumRows + i) = val;
}
// Set the i-th triple in the j-th column to u's three values
inline void MatrixRmn::SetTriple(long i, long j, const VectorR3& u)
{
long ii = 3 * i;
assert(0 <= i && ii + 2 < NumRows && 0 <= j && j < NumCols);
u.Dump(x + j * NumRows + ii);
}
// Set to be equal to the identity matrix
inline void MatrixRmn::SetIdentity()
{
assert(NumRows == NumCols);
SetZero();
SetDiagonalEntries(1.0);
}
inline MatrixRmn& MatrixRmn::operator*=(double mult)
{
double* aPtr = x;
for (long i = NumRows * NumCols; i > 0; i--)
{
(*(aPtr++)) *= mult;
}
return (*this);
}
inline MatrixRmn& MatrixRmn::AddScaled(const MatrixRmn& B, double factor)
{
assert(NumRows == B.NumRows && NumCols == B.NumCols);
double* aPtr = x;
double* bPtr = B.x;
for (long i = NumRows * NumCols; i > 0; i--)
{
(*(aPtr++)) += (*(bPtr++)) * factor;
}
return (*this);
}
inline MatrixRmn& MatrixRmn::operator+=(const MatrixRmn& B)
{
assert(NumRows == B.NumRows && NumCols == B.NumCols);
double* aPtr = x;
double* bPtr = B.x;
for (long i = NumRows * NumCols; i > 0; i--)
{
(*(aPtr++)) += *(bPtr++);
}
return (*this);
}
inline MatrixRmn& MatrixRmn::operator-=(const MatrixRmn& B)
{
assert(NumRows == B.NumRows && NumCols == B.NumCols);
double* aPtr = x;
double* bPtr = B.x;
for (long i = NumRows * NumCols; i > 0; i--)
{
(*(aPtr++)) -= *(bPtr++);
}
return (*this);
}
inline double MatrixRmn::FrobeniusNormSq() const
{
double* aPtr = x;
double result = 0.0;
for (long i = NumRows * NumCols; i > 0; i--)
{
result += Square(*(aPtr++));
}
return result;
}
// Helper routine to calculate dot product
inline double MatrixRmn::DotArray(long length, const double* ptrA, long strideA, const double* ptrB, long strideB)
{
double result = 0.0;
for (; length > 0; length--)
{
result += (*ptrA) * (*ptrB);
ptrA += strideA;
ptrB += strideB;
}
return result;
}
// Helper routine: copies and scales an array (src and dest may be equal, or overlap)
inline void MatrixRmn::CopyArrayScale(long length, const double* from, long fromStride, double* to, long toStride, double scale)
{
for (; length > 0; length--)
{
*to = (*from) * scale;
from += fromStride;
to += toStride;
}
}
// Helper routine: adds a scaled array
// fromArray = toArray*scale.
inline void MatrixRmn::AddArrayScale(long length, const double* from, long fromStride, double* to, long toStride, double scale)
{
for (; length > 0; length--)
{
*to += (*from) * scale;
from += fromStride;
to += toStride;
}
}
#endif //MATRIX_RMN_H

View file

@ -0,0 +1,140 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include <math.h>
#include <cmath>
#include "LinearR3.h"
#if 0
/****************************************************************
Axes
*****************************************************************/
static float xx[] = {
0., 1., 0., 1.
};
static float xy[] = {
-.5, .5, .5, -.5
};
static int xorder[] = {
1, 2, -3, 4
};
static float yx[] = {
0., 0., -.5, .5
};
static float yy[] = {
0.f, .6f, 1.f, 1.f
};
static int yorder[] = {
1, 2, 3, -2, 4
};
static float zx[] = {
1., 0., 1., 0., .25, .75
};
static float zy[] = {
.5, .5, -.5, -.5, 0., 0.
};
static int zorder[] = {
1, 2, 3, 4, -5, 6
};
#endif
#define LENFRAC 0.10
#define BASEFRAC 1.10
/****************************************************************
Arrow
*****************************************************************/
/* size of wings as fraction of length: */
#define WINGS 0.10
/* axes: */
#define X 1
#define Y 2
#define Z 3
/* x, y, z, axes: */
//static float axx[3] = { 1., 0., 0. };
//static float ayy[3] = { 0., 1., 0. };
//static float azz[3] = { 0., 0., 1. };
/* function declarations: */
void cross(float[3], float[3], float[3]);
float dot(float[3], float[3]);
float unit(float[3], float[3]);
float dot(float v1[3], float v2[3])
{
return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]);
}
void cross(float v1[3], float v2[3], float vout[3])
{
float tmp[3];
tmp[0] = v1[1] * v2[2] - v2[1] * v1[2];
tmp[1] = v2[0] * v1[2] - v1[0] * v2[2];
tmp[2] = v1[0] * v2[1] - v2[0] * v1[1];
vout[0] = tmp[0];
vout[1] = tmp[1];
vout[2] = tmp[2];
}
float unit(float vin[3], float vout[3])
{
float dist, f;
dist = vin[0] * vin[0] + vin[1] * vin[1] + vin[2] * vin[2];
if (dist > 0.0)
{
dist = std::sqrt(dist);
f = 1. / dist;
vout[0] = f * vin[0];
vout[1] = f * vin[1];
vout[2] = f * vin[2];
}
else
{
vout[0] = vin[0];
vout[1] = vin[1];
vout[2] = vin[2];
}
return (dist);
}

View file

@ -0,0 +1,87 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include <math.h>
#include "LinearR3.h"
#include "MathMisc.h"
#include "Node.h"
extern int RotAxesOn;
Node::Node(const VectorR3& attach, const VectorR3& v, double size, Purpose purpose, double minTheta, double maxTheta, double restAngle)
{
Node::freezed = false;
Node::size = size;
Node::purpose = purpose;
seqNumJoint = -1;
seqNumEffector = -1;
Node::attach = attach; // Global attachment point when joints are at zero angle
r.Set(0.0, 0.0, 0.0); // r will be updated when this node is inserted into tree
Node::v = v; // Rotation axis when joints at zero angles
theta = 0.0;
Node::minTheta = minTheta;
Node::maxTheta = maxTheta;
Node::restAngle = restAngle;
left = right = realparent = 0;
}
// Compute the global position of a single node
void Node::ComputeS(void)
{
Node* y = this->realparent;
Node* w = this;
s = r; // Initialize to local (relative) position
while (y)
{
s.Rotate(y->theta, y->v);
y = y->realparent;
w = w->realparent;
s += w->r;
}
}
// Compute the global rotation axis of a single node
void Node::ComputeW(void)
{
Node* y = this->realparent;
w = v; // Initialize to local rotation axis
while (y)
{
w.Rotate(y->theta, y->v);
y = y->realparent;
}
}
void Node::PrintNode()
{
cerr << "Attach : (" << attach << ")\n";
cerr << "r : (" << r << ")\n";
cerr << "s : (" << s << ")\n";
cerr << "w : (" << w << ")\n";
cerr << "realparent : " << realparent->seqNumJoint << "\n";
}
void Node::InitNode()
{
theta = 0.0;
}

View file

@ -0,0 +1,109 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#ifndef _CLASS_NODE
#define _CLASS_NODE
#include "LinearR3.h"
enum Purpose
{
JOINT,
EFFECTOR
};
class VectorR3;
class Node
{
friend class Tree;
public:
Node(const VectorR3&, const VectorR3&, double, Purpose, double minTheta = -PI, double maxTheta = PI, double restAngle = 0.);
void PrintNode();
void InitNode();
const VectorR3& GetAttach() const { return attach; }
double GetTheta() const { return theta; }
double AddToTheta(double& delta)
{
//double orgTheta = theta;
theta += delta;
#if 0
if (theta < minTheta)
theta = minTheta;
if (theta > maxTheta)
theta = maxTheta;
double actualDelta = theta - orgTheta;
delta = actualDelta;
#endif
return theta;
}
double UpdateTheta(double& delta)
{
theta = delta;
return theta;
}
const VectorR3& GetS() const { return s; }
const VectorR3& GetW() const { return w; }
double GetMinTheta() const { return minTheta; }
double GetMaxTheta() const { return maxTheta; }
double GetRestAngle() const { return restAngle; };
void SetTheta(double newTheta) { theta = newTheta; }
void ComputeS(void);
void ComputeW(void);
bool IsEffector() const { return purpose == EFFECTOR; }
bool IsJoint() const { return purpose == JOINT; }
int GetEffectorNum() const { return seqNumEffector; }
int GetJointNum() const { return seqNumJoint; }
bool IsFrozen() const { return freezed; }
void Freeze() { freezed = true; }
void UnFreeze() { freezed = false; }
//private:
bool freezed; // Is this node frozen?
int seqNumJoint; // sequence number if this node is a joint
int seqNumEffector; // sequence number if this node is an effector
double size; // size
Purpose purpose; // joint / effector / both
VectorR3 attach; // attachment point
VectorR3 r; // relative position vector
VectorR3 v; // rotation axis
double theta; // joint angle (radian)
double minTheta; // lower limit of joint angle
double maxTheta; // upper limit of joint angle
double restAngle; // rest position angle
VectorR3 s; // GLobal Position
VectorR3 w; // Global rotation axis
Node* left; // left child
Node* right; // right sibling
Node* realparent; // pointer to real parent
};
#endif

View file

@ -0,0 +1,293 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
//
// Spherical Operations Classes
//
//
// B. SphericalInterpolator
//
// OrientationR3
//
// A. Quaternion
//
// B. RotationMapR3 // Elsewhere
//
// C. EulerAnglesR3 // TO DO
//
//
// Functions for spherical operations
// A. Many routines for rotation and averaging on a sphere
//
#ifndef SPHERICAL_H
#define SPHERICAL_H
#include "LinearR3.h"
#include "LinearR4.h"
#include "MathMisc.h"
class SphericalInterpolator; // Spherical linear interpolation of vectors
class SphericalBSpInterpolator; // Spherical Bspline interpolation of vector
class Quaternion; // Quaternion (x,y,z,w) values.
class EulerAnglesR3; // Euler Angles
// *****************************************************
// SphericalInterpolator class *
// - Does linear interpolation (slerp-ing) *
// * * * * * * * * * * * * * * * * * * * * * * * * * * *
class SphericalInterpolator
{
private:
VectorR3 startDir, endDir; // Unit vectors (starting and ending)
double startLen, endLen; // Magnitudes of the vectors
double rotRate; // Angle between start and end vectors
public:
SphericalInterpolator(const VectorR3& u, const VectorR3& v);
VectorR3 InterValue(double frac) const;
};
// ***************************************************************
// * Quaternion class - prototypes *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
class Quaternion
{
public:
double x, y, z, w;
public:
Quaternion() : x(0.0), y(0.0), z(0.0), w(1.0){};
Quaternion(double, double, double, double);
inline Quaternion& Set(double xx, double yy, double zz, double ww);
inline Quaternion& Set(const VectorR4&);
Quaternion& Set(const EulerAnglesR3&);
Quaternion& Set(const RotationMapR3&);
Quaternion& SetRotate(const VectorR3&);
Quaternion& SetIdentity(); // Set to the identity map
Quaternion Inverse() const; // Return the Inverse
Quaternion& Invert(); // Invert this quaternion
double Angle(); // Angle of rotation
double Norm(); // Norm of x,y,z component
Quaternion& operator*=(const Quaternion&);
};
Quaternion operator*(const Quaternion&, const Quaternion&);
inline Quaternion ToQuat(const VectorR4& v)
{
return Quaternion(v.x, v.y, v.z, v.w);
}
inline double Quaternion::Norm()
{
return sqrt(x * x + y * y + z * z);
}
inline double Quaternion::Angle()
{
double halfAngle = asin(Norm());
return halfAngle + halfAngle;
}
// ****************************************************************
// Solid Geometry Routines *
// ****************************************************************
// Compute the angle formed by two geodesics on the unit sphere.
// Three unit vectors u,v,w specify the geodesics u-v and v-w which
// meet at vertex uv. The angle from v-w to v-u is returned. This
// is always in the range [0, 2PI).
double SphereAngle(const VectorR3& u, const VectorR3& v, const VectorR3& w);
// Compute the area of a triangle on the unit sphere. Three unit vectors
// specify the corners of the triangle in COUNTERCLOCKWISE order.
inline double SphericalTriangleArea(
const VectorR3& u, const VectorR3& v, const VectorR3& w)
{
double AngleA = SphereAngle(u, v, w);
double AngleB = SphereAngle(v, w, u);
double AngleC = SphereAngle(w, u, v);
return (AngleA + AngleB + AngleC - PI);
}
// ****************************************************************
// Spherical Mean routines *
// ****************************************************************
// Weighted sum of vectors
VectorR3 WeightedSum(long Num, const VectorR3 vv[], const double weights[]);
VectorR4 WeightedSum(long Num, const VectorR4 vv[], const double weights[]);
// Weighted average of vectors on the sphere.
// Sum of weights should equal one (but no checking is done)
VectorR3 ComputeMeanSphere(long Num, const VectorR3 vv[], const double weights[],
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
VectorR3 ComputeMeanSphere(long Num, const VectorR3 vv[], const double weights[],
const VectorR3& InitialVec,
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
VectorR4 ComputeMeanSphere(long Num, const VectorR4 vv[], const double weights[],
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
Quaternion ComputeMeanQuat(long Num, const Quaternion qq[], const double weights[],
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
// Next functions mostly for internal use.
// It takes an initial estimate InitialVec (and a flag for
// indicating quaternions).
VectorR4 ComputeMeanSphere(long Num, const VectorR4 vv[], const double weights[],
const VectorR4& InitialVec, int QuatFlag = 0,
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
const int SPHERICAL_NOTQUAT = 0;
const int SPHERICAL_QUAT = 1;
// Slow version, mostly for testing
VectorR3 ComputeMeanSphereSlow(long Num, const VectorR3 vv[], const double weights[],
double tolerance = 1.0e-16, double bkuptolerance = 5.0e-16);
VectorR4 ComputeMeanSphereSlow(long Num, const VectorR4 vv[], const double weights[],
double tolerance = 1.0e-16, double bkuptolerance = 5.0e-16);
VectorR3 ComputeMeanSphereOld(long Num, const VectorR3 vv[], const double weights[],
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
VectorR4 ComputeMeanSphereOld(long Num, const VectorR4 vv[], const double weights[],
const VectorR4& InitialVec, int QuatFlag,
double tolerance = 1.0e-15, double bkuptolerance = 1.0e-13);
// Solves a system of spherical-mean equalities, where the system is
// given as a tridiagonal matrix.
void SolveTriDiagSphere(int numPoints,
const double* tridiagvalues, const VectorR3* c,
VectorR3* p,
double accuracy = 1.0e-15, double bkupaccuracy = 1.0e-13);
void SolveTriDiagSphere(int numPoints,
const double* tridiagvalues, const VectorR4* c,
VectorR4* p,
double accuracy = 1.0e-15, double bkupaccuracy = 1.0e-13);
// The "Slow" version uses a simpler but slower iteration with a linear rate of
// convergence. The base version uses a Newton iteration with a quadratic
// rate of convergence.
void SolveTriDiagSphereSlow(int numPoints,
const double* tridiagvalues, const VectorR3* c,
VectorR3* p,
double accuracy = 1.0e-15, double bkupaccuracy = 5.0e-15);
void SolveTriDiagSphereSlow(int numPoints,
const double* tridiagvalues, const VectorR4* c,
VectorR4* p,
double accuracy = 1.0e-15, double bkupaccuracy = 5.0e-15);
// The "Unstable" version probably shouldn't be used except for very short sequences
// of knots. Mostly it's used for testing purposes now.
void SolveTriDiagSphereUnstable(int numPoints,
const double* tridiagvalues, const VectorR3* c,
VectorR3* p,
double accuracy = 1.0e-15, double bkupaccuracy = 1.0e-13);
void SolveTriDiagSphereHelperUnstable(int numPoints,
const double* tridiagvalues, const VectorR3* c,
const VectorR3& p0value,
VectorR3* p,
double accuracy = 1.0e-15, double bkupaccuracy = 1.0e-13);
// ***************************************************************
// * Quaternion class - inlined member functions *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
inline VectorR4::VectorR4(const Quaternion& q)
: x(q.x), y(q.y), z(q.z), w(q.w)
{
}
inline VectorR4& VectorR4::Set(const Quaternion& q)
{
x = q.x;
y = q.y;
z = q.z;
w = q.w;
return *this;
}
inline Quaternion::Quaternion(double xx, double yy, double zz, double ww)
: x(xx), y(yy), z(zz), w(ww)
{
}
inline Quaternion& Quaternion::Set(double xx, double yy, double zz, double ww)
{
x = xx;
y = yy;
z = zz;
w = ww;
return *this;
}
inline Quaternion& Quaternion::Set(const VectorR4& u)
{
x = u.x;
y = u.y;
z = u.z;
w = u.w;
return *this;
}
inline Quaternion& Quaternion::SetIdentity()
{
x = y = z = 0.0;
w = 1.0;
return *this;
}
inline Quaternion operator*(const Quaternion& q1, const Quaternion& q2)
{
Quaternion q(q1);
q *= q2;
return q;
}
inline Quaternion& Quaternion::operator*=(const Quaternion& q)
{
double wnew = w * q.w - (x * q.x + y * q.y + z * q.z);
double xnew = w * q.x + q.w * x + (y * q.z - z * q.y);
double ynew = w * q.y + q.w * y + (z * q.x - x * q.z);
z = w * q.z + q.w * z + (x * q.y - y * q.x);
w = wnew;
x = xnew;
y = ynew;
return *this;
}
inline Quaternion Quaternion::Inverse() const // Return the Inverse
{
return (Quaternion(x, y, z, -w));
}
inline Quaternion& Quaternion::Invert() // Invert this quaternion
{
w = -w;
return *this;
}
#endif // SPHERICAL_H

View file

@ -0,0 +1,231 @@
/*
*
* Inverse Kinematics software, with several solvers including
* Selectively Damped Least Squares Method
* Damped Least Squares Method
* Pure Pseudoinverse Method
* Jacobian Transpose Method
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/index.html
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
//
// VectorRn: Vector over Rn (Variable length vector)
//
#include <iostream>
using namespace std;
#include "LinearR3.h"
#include "Tree.h"
#include "Node.h"
Tree::Tree()
{
root = 0;
nNode = nEffector = nJoint = 0;
}
void Tree::SetSeqNum(Node* node)
{
switch (node->purpose)
{
case JOINT:
node->seqNumJoint = nJoint++;
node->seqNumEffector = -1;
break;
case EFFECTOR:
node->seqNumJoint = -1;
node->seqNumEffector = nEffector++;
break;
}
}
void Tree::InsertRoot(Node* root)
{
assert(nNode == 0);
nNode++;
Tree::root = root;
root->r = root->attach;
assert(!(root->left || root->right));
SetSeqNum(root);
}
void Tree::InsertLeftChild(Node* parent, Node* child)
{
assert(parent);
nNode++;
parent->left = child;
child->realparent = parent;
child->r = child->attach - child->realparent->attach;
assert(!(child->left || child->right));
SetSeqNum(child);
}
void Tree::InsertRightSibling(Node* parent, Node* child)
{
assert(parent);
nNode++;
parent->right = child;
child->realparent = parent->realparent;
child->r = child->attach - child->realparent->attach;
assert(!(child->left || child->right));
SetSeqNum(child);
}
// Search recursively below "node" for the node with index value.
Node* Tree::SearchJoint(Node* node, int index)
{
Node* ret;
if (node != 0)
{
if (node->seqNumJoint == index)
{
return node;
}
else
{
if ((ret = SearchJoint(node->left, index)))
{
return ret;
}
if ((ret = SearchJoint(node->right, index)))
{
return ret;
}
return NULL;
}
}
else
{
return NULL;
}
}
// Get the joint with the index value
Node* Tree::GetJoint(int index)
{
return SearchJoint(root, index);
}
// Search recursively below node for the end effector with the index value
Node* Tree::SearchEffector(Node* node, int index)
{
Node* ret;
if (node != 0)
{
if (node->seqNumEffector == index)
{
return node;
}
else
{
if ((ret = SearchEffector(node->left, index)))
{
return ret;
}
if ((ret = SearchEffector(node->right, index)))
{
return ret;
}
return NULL;
}
}
else
{
return NULL;
}
}
// Get the end effector for the index value
Node* Tree::GetEffector(int index)
{
return SearchEffector(root, index);
}
// Returns the global position of the effector.
const VectorR3& Tree::GetEffectorPosition(int index)
{
Node* effector = GetEffector(index);
assert(effector);
return (effector->s);
}
void Tree::ComputeTree(Node* node)
{
if (node != 0)
{
node->ComputeS();
node->ComputeW();
ComputeTree(node->left);
ComputeTree(node->right);
}
}
void Tree::Compute(void)
{
ComputeTree(root);
}
void Tree::PrintTree(Node* node)
{
if (node != 0)
{
node->PrintNode();
PrintTree(node->left);
PrintTree(node->right);
}
}
void Tree::Print(void)
{
PrintTree(root);
cout << "\n";
}
// Recursively initialize tree below the node
void Tree::InitTree(Node* node)
{
if (node != 0)
{
node->InitNode();
InitTree(node->left);
InitTree(node->right);
}
}
// Initialize all nodes in the tree
void Tree::Init(void)
{
InitTree(root);
}
void Tree::UnFreezeTree(Node* node)
{
if (node != 0)
{
node->UnFreeze();
UnFreezeTree(node->left);
UnFreezeTree(node->right);
}
}
void Tree::UnFreeze(void)
{
UnFreezeTree(root);
}

View file

@ -0,0 +1,96 @@
/*
*
* Inverse Kinematics software, with several solvers including
* Selectively Damped Least Squares Method
* Damped Least Squares Method
* Pure Pseudoinverse Method
* Jacobian Transpose Method
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/index.html
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
#include "LinearR3.h"
#include "Node.h"
#ifndef _CLASS_TREE
#define _CLASS_TREE
class Tree
{
public:
Tree();
int GetNumNode() const { return nNode; }
int GetNumEffector() const { return nEffector; }
int GetNumJoint() const { return nJoint; }
void InsertRoot(Node*);
void InsertLeftChild(Node* parent, Node* child);
void InsertRightSibling(Node* parent, Node* child);
// Accessors based on node numbers
Node* GetJoint(int);
Node* GetEffector(int);
const VectorR3& GetEffectorPosition(int);
// Accessors for tree traversal
Node* GetRoot() const { return root; }
Node* GetSuccessor(const Node*) const;
Node* GetParent(const Node* node) const { return node->realparent; }
void Compute();
void Print();
void Init();
void UnFreeze();
private:
Node* root;
int nNode; // nNode = nEffector + nJoint
int nEffector;
int nJoint;
void SetSeqNum(Node*);
Node* SearchJoint(Node*, int);
Node* SearchEffector(Node*, int);
void ComputeTree(Node*);
void PrintTree(Node*);
void InitTree(Node*);
void UnFreezeTree(Node*);
};
inline Node* Tree::GetSuccessor(const Node* node) const
{
if (node->left)
{
return node->left;
}
while (true)
{
if (node->right)
{
return (node->right);
}
node = node->realparent;
if (!node)
{
return 0; // Back to root, finished traversal
}
}
}
#endif

View file

@ -0,0 +1,48 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
//
// VectorRn: Vector over Rn (Variable length vector)
//
#include "VectorRn.h"
VectorRn VectorRn::WorkVector;
double VectorRn::MaxAbs() const
{
double result = 0.0;
double* t = x;
for (long i = length; i > 0; i--)
{
if ((*t) > result)
{
result = *t;
}
else if (-(*t) > result)
{
result = -(*t);
}
t++;
}
return result;
}

View file

@ -0,0 +1,275 @@
/*
*
* Mathematics Subpackage (VrMath)
*
*
* Author: Samuel R. Buss, sbuss@ucsd.edu.
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*
*
*/
//
// VectorRn: Vector over Rn (Variable length vector)
//
// Not very sophisticated yet. Needs more functionality
// To do: better handling of resizing.
//
#ifndef VECTOR_RN_H
#define VECTOR_RN_H
#include <math.h>
#include <assert.h>
#include "LinearR3.h"
class VectorRn
{
friend class MatrixRmn;
public:
VectorRn(); // Null constructor
VectorRn(long length); // Constructor with length
~VectorRn(); // Destructor
void SetLength(long newLength);
long GetLength() const { return length; }
void SetZero();
void Fill(double d);
void Load(const double* d);
void LoadScaled(const double* d, double scaleFactor);
void Set(const VectorRn& src);
// Two access methods identical in functionality
// Subscripts are ZERO-BASED!!
const double& operator[](long i) const
{
assert(0 <= i && i < length);
return *(x + i);
}
double& operator[](long i)
{
assert(0 <= i && i < length);
return *(x + i);
}
double Get(long i) const
{
assert(0 <= i && i < length);
return *(x + i);
}
// Use GetPtr to get pointer into the array (efficient)
// Is friendly in that anyone can change the array contents (be careful!)
const double* GetPtr(long i) const
{
assert(0 <= i && i < length);
return (x + i);
}
double* GetPtr(long i)
{
assert(0 <= i && i < length);
return (x + i);
}
const double* GetPtr() const { return x; }
double* GetPtr() { return x; }
void Set(long i, double val) { assert(0 <= i && i < length), *(x + i) = val; }
void SetTriple(long i, const VectorR3& u);
VectorRn& operator+=(const VectorRn& src);
VectorRn& operator-=(const VectorRn& src);
void AddScaled(const VectorRn& src, double scaleFactor);
VectorRn& operator*=(double f);
double NormSq() const;
double Norm() const { return sqrt(NormSq()); }
double MaxAbs() const;
private:
long length; // Logical or actual length
long AllocLength; // Allocated length
double* x; // Array of vector entries
static VectorRn WorkVector; // Serves as a temporary vector
static VectorRn& GetWorkVector() { return WorkVector; }
static VectorRn& GetWorkVector(long len)
{
WorkVector.SetLength(len);
return WorkVector;
}
};
inline VectorRn::VectorRn()
{
length = 0;
AllocLength = 0;
x = 0;
}
inline VectorRn::VectorRn(long initLength)
{
length = 0;
AllocLength = 0;
x = 0;
SetLength(initLength);
}
inline VectorRn::~VectorRn()
{
delete[] x;
}
// Resize.
// If the array is shortened, the information about the allocated length is lost.
inline void VectorRn::SetLength(long newLength)
{
assert(newLength > 0);
if (newLength > AllocLength)
{
delete[] x;
AllocLength = Max(newLength, AllocLength << 1);
x = new double[AllocLength];
}
length = newLength;
}
// Zero out the entire vector
inline void VectorRn::SetZero()
{
double* target = x;
for (long i = length; i > 0; i--)
{
*(target++) = 0.0;
}
}
// Set the value of the i-th triple of entries in the vector
inline void VectorRn::SetTriple(long i, const VectorR3& u)
{
long j = 3 * i;
assert(0 <= j && j + 2 < length);
u.Dump(x + j);
}
inline void VectorRn::Fill(double d)
{
double* to = x;
for (long i = length; i > 0; i--)
{
*(to++) = d;
}
}
inline void VectorRn::Load(const double* d)
{
double* to = x;
for (long i = length; i > 0; i--)
{
*(to++) = *(d++);
}
}
inline void VectorRn::LoadScaled(const double* d, double scaleFactor)
{
double* to = x;
for (long i = length; i > 0; i--)
{
*(to++) = (*(d++)) * scaleFactor;
}
}
inline void VectorRn::Set(const VectorRn& src)
{
assert(src.length == this->length);
double* to = x;
double* from = src.x;
for (long i = length; i > 0; i--)
{
*(to++) = *(from++);
}
}
inline VectorRn& VectorRn::operator+=(const VectorRn& src)
{
assert(src.length == this->length);
double* to = x;
double* from = src.x;
for (long i = length; i > 0; i--)
{
*(to++) += *(from++);
}
return *this;
}
inline VectorRn& VectorRn::operator-=(const VectorRn& src)
{
assert(src.length == this->length);
double* to = x;
double* from = src.x;
for (long i = length; i > 0; i--)
{
*(to++) -= *(from++);
}
return *this;
}
inline void VectorRn::AddScaled(const VectorRn& src, double scaleFactor)
{
assert(src.length == this->length);
double* to = x;
double* from = src.x;
for (long i = length; i > 0; i--)
{
*(to++) += (*(from++)) * scaleFactor;
}
}
inline VectorRn& VectorRn::operator*=(double f)
{
double* target = x;
for (long i = length; i > 0; i--)
{
*(target++) *= f;
}
return *this;
}
inline double VectorRn::NormSq() const
{
double* target = x;
double res = 0.0;
for (long i = length; i > 0; i--)
{
res += (*target) * (*target);
target++;
}
return res;
}
inline double Dot(const VectorRn& u, const VectorRn& v)
{
assert(u.GetLength() == v.GetLength());
double res = 0.0;
const double* p = u.GetPtr();
const double* q = v.GetPtr();
for (long i = u.GetLength(); i > 0; i--)
{
res += (*(p++)) * (*(q++));
}
return res;
}
#endif //VECTOR_RN_H

View file

@ -0,0 +1,14 @@
project "BussIK"
kind "StaticLib"
includedirs {
"."
}
if os.is("Linux") then
buildoptions{"-fPIC"}
end
files {
"*.cpp",
"*.h",
}