tahoma2d/toonz/sources/toonzlib/ikengine.cpp

127 lines
3.8 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "toonz/ikengine.h"
#include "toonz/ikjacobian.h"
2016-06-15 18:43:10 +12:00
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;
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
// 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);
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
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);
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
void IKEngine::unlock(int index) {
assert(index > -1 && index < m_skeleton.getNodeCount());
m_skeleton.setPurpose(index, IKNode::JOINT);
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
bool IKEngine::isLocked(int index) {
assert(index > -1 && index < m_skeleton.getNodeCount());
return m_skeleton.getNode(index)->IsEffector();
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
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;
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
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;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// 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);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// assegno un indice alla sequenza dei giunti (nodi -end effectors)
setSequenceJoints();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
target.push_back(pos);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
Jacobian jacobian(&m_skeleton, target);
target.pop_back();
for (int i = 0; i < 250; i++) doUpdateStep(jacobian);
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
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();
}
2016-03-19 06:57:51 +13:00
}
// Assegno gli indici nella sequenza dei giunti
2016-06-15 18:43:10 +12:00
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++;
}
}
2016-03-19 06:57:51 +13:00
}