#include <math.h>
#include <maya/MIOStream.h>
#include <maya/MFnPlugin.h>
#include <maya/MObject.h>
#include <maya/MDagPath.h>
#include <maya/MString.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MQuaternion.h>
#include <AwPoint.h>
#include <AwVector.h>
#include <AwMatrix.h>
#include <AwQuaternion.h>
#include <maya/MPxIkSolverNode.h>
#include <maya/MIkHandleGroup.h>
#include <maya/MFnIkHandle.h>
#include <maya/MFnIkEffector.h>
#include <maya/MFnIkJoint.h>
#include <maya/MArgList.h>
#include <maya/MPxCommand.h>
#include <maya/MGlobal.h>
#include <maya/MSceneMessage.h>
#include <maya/MSelectionList.h>
#define kSolverType "ik2Bsolver"
#define kPi 3.14159265358979323846264338327950
#define kEpsilon 1.0e-5
#define absoluteValue(x) ((x) < 0 ? (-(x)) : (x))
public:
ik2Bsolver ();
~ik2Bsolver () override;
static void* creator();
private:
AwVector poleVectorFromHandle(
const MDagPath &handlePath);
double twistFromHandle(
const MDagPath &handlePath);
};
void solveIK(const AwPoint &startJointPos,
const AwPoint &midJointPos,
const AwPoint &effectorPos,
const AwPoint &handlePos,
const AwVector &poleVector,
double twistValue,
AwQuaternion &qStart,
AwQuaternion &qMid);
MTypeId ik2Bsolver::id(0x58000030);
ik2Bsolver::ik2Bsolver()
{
}
ik2Bsolver::~ik2Bsolver() {}
void ik2Bsolver::postConstructor()
{
setRotatePlane(true);
}
void* ik2Bsolver::creator()
{
return new ik2Bsolver;
}
{
return MS::kSuccess;
}
MString ik2Bsolver::solverTypeName() const
{
}
{
if (NULL == handle_group) {
return MS::kFailure;
}
handleFn.getEffector(effectorPath);
handleFn.getStartJoint(startJointPath);
double startJointPrefAngle[3];
double midJointPrefAngle[3];
startJointFn.getPreferedAngle(startJointPrefAngle);
midJointFn.getPreferedAngle(midJointPrefAngle);
startJointFn.setRotation(startJointPrefAngle,
startJointFn.rotationOrder());
midJointFn.setRotation(midJointPrefAngle,
midJointFn.rotationOrder());
AwVector poleVector = poleVectorFromHandle(handlePath);
double twistValue = twistFromHandle(handlePath);
AwQuaternion qStart, qMid;
solveIK(startJointPos,
midJointPos,
effectorPos,
handlePos,
poleVector,
twistValue,
qStart,
qMid);
return MS::kSuccess;
}
void solveIK(const AwPoint &startJointPos,
const AwPoint &midJointPos,
const AwPoint &effectorPos,
const AwPoint &handlePos,
const AwVector &poleVector,
double twistValue,
AwQuaternion &qStart,
AwQuaternion &qMid)
{
AwVector vector1 = midJointPos - startJointPos;
AwVector vector2 = effectorPos - midJointPos;
AwVector vectorH = handlePos - startJointPos;
AwVector vectorE = effectorPos - startJointPos;
double length1 = vector1.length();
double length2 = vector2.length();
double lengthH = vectorH.length();
AwVector vectorO =
vector1 - vectorE*((vector1*vectorE)/(vectorE*vectorE));
double vectorAngle12 = vector1.angle(vector2);
AwVector vectorCross12 = vector1^vector2;
double lengthHsquared = lengthH*lengthH;
double cos_theta =
(lengthHsquared - length1*length1 - length2*length2)
/(2*length1*length2);
if (cos_theta > 1)
cos_theta = 1;
else if (cos_theta < -1)
cos_theta = -1;
double theta = acos(cos_theta);
AwQuaternion q12(theta - vectorAngle12, vectorCross12);
vector2 = vector2.rotateBy(q12);
vectorE = vector1 + vector2;
AwQuaternion qEH(vectorE, vectorH);
vector1 = vector1.rotateBy(qEH);
if (vector1.isParallel(vectorH))
vector1 = vectorO.rotateBy(qEH);
AwQuaternion qNP;
if (!poleVector.isParallel(vectorH) && (lengthHsquared != 0)) {
AwVector vectorN =
vector1 - vectorH*((vector1*vectorH)/lengthHsquared);
AwVector vectorP =
poleVector - vectorH*((poleVector*vectorH)/lengthHsquared);
double dotNP = (vectorN*vectorP)/(vectorN.length()*vectorP.length());
if (absoluteValue(dotNP + 1.0) < kEpsilon) {
AwQuaternion qNP1(kPi, vectorH);
qNP = qNP1;
}
else {
AwQuaternion qNP2(vectorN, vectorP);
qNP = qNP2;
}
}
AwQuaternion qTwist(twistValue, vectorH);
qMid = q12;
qStart = qEH*qNP*qTwist;
}
AwVector ik2Bsolver::poleVectorFromHandle(
const MDagPath &handlePath)
{
MPlug pvxPlug = handleFn.findPlug(
"pvx",
true);
MPlug pvyPlug = handleFn.findPlug(
"pvy",
true);
MPlug pvzPlug = handleFn.findPlug(
"pvz",
true);
double pvxValue, pvyValue, pvzValue;
AwVector poleVector(pvxValue, pvyValue, pvzValue);
return poleVector;
}
double ik2Bsolver::twistFromHandle(
const MDagPath &handlePath)
{
MPlug twistPlug = handleFn.findPlug(
"twist",
true);
double twistValue;
return twistValue;
}
class addIK2BsolverCallbacks :
public MPxCommand {
public:
addIK2BsolverCallbacks() {};
static void* creator();
static MCallbackId afterNewId;
static MCallbackId afterOpenId;
};
MCallbackId addIK2BsolverCallbacks::afterNewId;
MCallbackId addIK2BsolverCallbacks::afterOpenId;
void *addIK2BsolverCallbacks::creator()
{
return new addIK2BsolverCallbacks;
}
void createIK2BsolverAfterNew(void *clientData)
{
}
void createIK2BsolverAfterOpen(void *clientData)
{
}
}
{
createIK2BsolverAfterNew);
createIK2BsolverAfterOpen);
return MS::kSuccess;
}
{
MFnPlugin plugin(obj, PLUGIN_COMPANY,
"2.5",
"Any");
status = plugin.registerNode("ik2Bsolver",
ik2Bsolver::id,
&ik2Bsolver::creator,
&ik2Bsolver::initialize,
if (!status) {
status.
perror(
"registerNode");
return status;
}
status = plugin.registerCommand("addIK2BsolverCallbacks",
addIK2BsolverCallbacks::creator);
if (!status) {
status.
perror(
"registerCommand");
return status;
}
return status;
}
{
status = plugin.deregisterNode(ik2Bsolver::id);
if (!status) {
status.
perror(
"deregisterNode");
return status;
}
status = plugin.deregisterCommand("addIK2BsolverCallbacks");
if (!status) {
status.
perror(
"deregisterCommand");
return status;
}
return status;
}