Blob Blame Raw


#include "toonz/ikengine.h"
#include "toonz/ikjacobian.h"

enum Method { JACOB_TRANS,
			  PURE_PSEUDO,
			  DLS,
			  SDLS,
			  COMPARE };

IKEngine::IKEngine()
{
}

int IKEngine::addJoint(const TPointD &pos, int indexParent)
{
	// TODO: evitare che si formino segmenti nulli
	//assert(m_joints.empty() || norm2(pos-m_joints.back())>0.000001);
	//assert(m_nodes[indexParent]);
	assert(m_skeleton.getNode(indexParent));
	m_skeleton.addNode(new IKNode());
	int index = m_skeleton.getNodeCount() - 1;
	m_skeleton.setNode(index, pos, IKNode::JOINT);
	m_skeleton.setParent(index, indexParent);
	return index;
}
//la root deve coincidere con un punto bloccato!
void IKEngine::setRoot(const TPointD &pos)
{
	m_skeleton.addNode(new IKNode());
	m_skeleton.setNode(0, pos, IKNode::JOINT);
	//m_skeleton.setParent(0,0);
	m_skeleton.setRoot(0);
}

void IKEngine::lock(int index)
{
	assert(index > -1 && index < m_skeleton.getNodeCount());
	m_skeleton.setPurpose(index, IKNode::EFFECTOR);
	IKNode *n = m_skeleton.getNode(index);
	TPointD pos = n->getPos();
	target.push_back(pos);
}
void IKEngine::unlock(int index)
{
	assert(index > -1 && index < m_skeleton.getNodeCount());
	m_skeleton.setPurpose(index, IKNode::JOINT);
}

bool IKEngine::isLocked(int index)
{
	assert(index > -1 && index < m_skeleton.getNodeCount());
	return m_skeleton.getNode(index)->IsEffector();
}

double IKEngine::getJointAngle(int index)
{
	assert(index > -1 && index < m_skeleton.getNodeCount());
	TPointD pos = m_skeleton.getNode(index)->getPos();
	TPointD u(1, 0);
	if (index != 0) {
		int parent = getJointParent(index);
		TPointD prevPos = m_skeleton.getNode(parent)->getPos();
		u = normalize(pos - prevPos);
	}
	TPointD v(-u.y, u.x);
	TPointD nextPos = m_skeleton.getNode(index + 1)->getPos();
	TPointD d = nextPos - pos;
	double theta = atan2(d * v, d * u);
	return theta;
}

void IKEngine::drag(TPointD &pos)
{
	//assert(index>-1 && index<m_skeleton.getNodeCount());
	// se lo scheletro รจ vuoto non succede nulla
	if (m_skeleton.getNodeCount() == 0)
		return;

	// afferro l'ultimo punto della catena
	int indexDrag = m_skeleton.getNodeCount() - 1;
	if (m_skeleton.getNode(indexDrag)->getParent()->IsEffector())
		return;
	m_skeleton.setPurpose(indexDrag, IKNode::EFFECTOR);

	//assegno un indice alla sequenza dei giunti (nodi -end effectors)
	setSequenceJoints();

	target.push_back(pos);

	Jacobian jacobian(&m_skeleton, target);
	target.pop_back();
	for (int i = 0; i < 250; i++)
		doUpdateStep(jacobian);
}

void IKEngine::doUpdateStep(Jacobian &jacobian)
{
	jacobian.computeJacobian(); // calcolo Jacobiano e il vettore deltaS
	int WhichMethod = DLS;

	bool clampingDetected = true;
	while (clampingDetected) {
		// Calcolo i cambiamenti dell'angolo
		switch (WhichMethod) {
		case JACOB_TRANS:
			jacobian.CalcDeltaThetasTranspose(); // Jacobian transpose method
			break;
		case DLS:
			jacobian.CalcDeltaThetasDLS(); // Damped least squares method
			break;
		case PURE_PSEUDO:
			jacobian.CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method
			break;
		case SDLS:
			jacobian.CalcDeltaThetasSDLS(); // Selectively damped least squares method
			break;
		default:
			jacobian.ZeroDeltaThetas();
			break;
		}

		jacobian.UpdateThetas(); // Aggiorno i valori di theta

		clampingDetected = jacobian.checkJointsLimit();
		//jacobian.UpdatedSClampValue();
	}
}

// Assegno gli indici nella sequenza dei giunti
void IKEngine::setSequenceJoints()
{
	int indexJoint = 0;
	for (int i = 0; i < (int)m_skeleton.getNodeCount(); i++) {
		IKNode *n = m_skeleton.getNode(i);
		IKNode::Purpose purpose = n->getPurpose();
		if (purpose != IKNode::EFFECTOR) {
			n->setSeqNumJoint(indexJoint);
			indexJoint++;
		}
	}
}