Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/ikengine.h"
Toshihiro Shimizu 890ddd
#include "toonz/ikjacobian.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum Method { JACOB_TRANS,
Toshihiro Shimizu 890ddd
			  PURE_PSEUDO,
Toshihiro Shimizu 890ddd
			  DLS,
Toshihiro Shimizu 890ddd
			  SDLS,
Toshihiro Shimizu 890ddd
			  COMPARE };
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
IKEngine::IKEngine()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int IKEngine::addJoint(const TPointD &pos, int indexParent)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// TODO: evitare che si formino segmenti nulli
Toshihiro Shimizu 890ddd
	//assert(m_joints.empty() || norm2(pos-m_joints.back())>0.000001);
Toshihiro Shimizu 890ddd
	//assert(m_nodes[indexParent]);
Toshihiro Shimizu 890ddd
	assert(m_skeleton.getNode(indexParent));
Toshihiro Shimizu 890ddd
	m_skeleton.addNode(new IKNode());
Toshihiro Shimizu 890ddd
	int index = m_skeleton.getNodeCount() - 1;
Toshihiro Shimizu 890ddd
	m_skeleton.setNode(index, pos, IKNode::JOINT);
Toshihiro Shimizu 890ddd
	m_skeleton.setParent(index, indexParent);
Toshihiro Shimizu 890ddd
	return index;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//la root deve coincidere con un punto bloccato!
Toshihiro Shimizu 890ddd
void IKEngine::setRoot(const TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_skeleton.addNode(new IKNode());
Toshihiro Shimizu 890ddd
	m_skeleton.setNode(0, pos, IKNode::JOINT);
Toshihiro Shimizu 890ddd
	//m_skeleton.setParent(0,0);
Toshihiro Shimizu 890ddd
	m_skeleton.setRoot(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void IKEngine::lock(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index > -1 && index < m_skeleton.getNodeCount());
Toshihiro Shimizu 890ddd
	m_skeleton.setPurpose(index, IKNode::EFFECTOR);
Toshihiro Shimizu 890ddd
	IKNode *n = m_skeleton.getNode(index);
Toshihiro Shimizu 890ddd
	TPointD pos = n->getPos();
Toshihiro Shimizu 890ddd
	target.push_back(pos);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
void IKEngine::unlock(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index > -1 && index < m_skeleton.getNodeCount());
Toshihiro Shimizu 890ddd
	m_skeleton.setPurpose(index, IKNode::JOINT);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool IKEngine::isLocked(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index > -1 && index < m_skeleton.getNodeCount());
Toshihiro Shimizu 890ddd
	return m_skeleton.getNode(index)->IsEffector();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double IKEngine::getJointAngle(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index > -1 && index < m_skeleton.getNodeCount());
Toshihiro Shimizu 890ddd
	TPointD pos = m_skeleton.getNode(index)->getPos();
Toshihiro Shimizu 890ddd
	TPointD u(1, 0);
Toshihiro Shimizu 890ddd
	if (index != 0) {
Toshihiro Shimizu 890ddd
		int parent = getJointParent(index);
Toshihiro Shimizu 890ddd
		TPointD prevPos = m_skeleton.getNode(parent)->getPos();
Toshihiro Shimizu 890ddd
		u = normalize(pos - prevPos);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TPointD v(-u.y, u.x);
Toshihiro Shimizu 890ddd
	TPointD nextPos = m_skeleton.getNode(index + 1)->getPos();
Toshihiro Shimizu 890ddd
	TPointD d = nextPos - pos;
Toshihiro Shimizu 890ddd
	double theta = atan2(d * v, d * u);
Toshihiro Shimizu 890ddd
	return theta;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void IKEngine::drag(TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//assert(index>-1 && index
Toshihiro Shimizu 890ddd
	// se lo scheletro รจ vuoto non succede nulla
Toshihiro Shimizu 890ddd
	if (m_skeleton.getNodeCount() == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// afferro l'ultimo punto della catena
Toshihiro Shimizu 890ddd
	int indexDrag = m_skeleton.getNodeCount() - 1;
Toshihiro Shimizu 890ddd
	if (m_skeleton.getNode(indexDrag)->getParent()->IsEffector())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_skeleton.setPurpose(indexDrag, IKNode::EFFECTOR);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//assegno un indice alla sequenza dei giunti (nodi -end effectors)
Toshihiro Shimizu 890ddd
	setSequenceJoints();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	target.push_back(pos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Jacobian jacobian(&m_skeleton, target);
Toshihiro Shimizu 890ddd
	target.pop_back();
Toshihiro Shimizu 890ddd
	for (int i = 0; i < 250; i++)
Toshihiro Shimizu 890ddd
		doUpdateStep(jacobian);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void IKEngine::doUpdateStep(Jacobian &jacobian)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	jacobian.computeJacobian(); // calcolo Jacobiano e il vettore deltaS
Toshihiro Shimizu 890ddd
	int WhichMethod = DLS;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool clampingDetected = true;
Toshihiro Shimizu 890ddd
	while (clampingDetected) {
Toshihiro Shimizu 890ddd
		// Calcolo i cambiamenti dell'angolo
Toshihiro Shimizu 890ddd
		switch (WhichMethod) {
Toshihiro Shimizu 890ddd
		case JACOB_TRANS:
Toshihiro Shimizu 890ddd
			jacobian.CalcDeltaThetasTranspose(); // Jacobian transpose method
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		case DLS:
Toshihiro Shimizu 890ddd
			jacobian.CalcDeltaThetasDLS(); // Damped least squares method
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		case PURE_PSEUDO:
Toshihiro Shimizu 890ddd
			jacobian.CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		case SDLS:
Toshihiro Shimizu 890ddd
			jacobian.CalcDeltaThetasSDLS(); // Selectively damped least squares method
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		default:
Toshihiro Shimizu 890ddd
			jacobian.ZeroDeltaThetas();
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		jacobian.UpdateThetas(); // Aggiorno i valori di theta
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		clampingDetected = jacobian.checkJointsLimit();
Toshihiro Shimizu 890ddd
		//jacobian.UpdatedSClampValue();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Assegno gli indici nella sequenza dei giunti
Toshihiro Shimizu 890ddd
void IKEngine::setSequenceJoints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int indexJoint = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)m_skeleton.getNodeCount(); i++) {
Toshihiro Shimizu 890ddd
		IKNode *n = m_skeleton.getNode(i);
Toshihiro Shimizu 890ddd
		IKNode::Purpose purpose = n->getPurpose();
Toshihiro Shimizu 890ddd
		if (purpose != IKNode::EFFECTOR) {
Toshihiro Shimizu 890ddd
			n->setSeqNumJoint(indexJoint);
Toshihiro Shimizu 890ddd
			indexJoint++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}