Merge remote-tracking branch 'upstream/master' into tahoma
This commit is contained in:
commit
f5fd4a4e34
7 changed files with 177 additions and 112 deletions
|
@ -65,7 +65,7 @@ public:
|
|||
\sa rotate270
|
||||
*/
|
||||
template <class T>
|
||||
inline TPointT<T> rotate90(const TPointT<T> &p) // counterclockwise
|
||||
inline TPointT<T> rotate90(const TPointT<T> &p) // 90 counterclockwise
|
||||
{
|
||||
return TPointT<T>(-p.y, p.x);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ inline TPointT<T> rotate90(const TPointT<T> &p) // counterclockwise
|
|||
\sa rotate90
|
||||
*/
|
||||
template <class T>
|
||||
inline TPointT<T> rotate270(const TPointT<T> &p) // clockwise
|
||||
inline TPointT<T> rotate270(const TPointT<T> &p) // 90 clockwise
|
||||
{
|
||||
return TPointT<T>(p.y, -p.x);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ inline TPointT<T> rotate270(const TPointT<T> &p) // clockwise
|
|||
/*!
|
||||
\relates TPointT
|
||||
*/
|
||||
template <class T> // prodotto scalare
|
||||
template <class T> // Scalar(dot) Product
|
||||
inline T operator*(const TPointT<T> &a, const TPointT<T> &b) {
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
@ -542,11 +542,11 @@ template class DVAPI TDimensionT<double>;
|
|||
//=============================================================================
|
||||
|
||||
//! Specifies the corners of a rectangle.
|
||||
/*!\arg \a x0 specifies the x-coordinate of the bottom-left corner of a
|
||||
rectangle.
|
||||
\arg \a y0 specifies the y-coordinate of the bottom-left corner of a rectangle.
|
||||
\arg \a x1 specifies the x-coordinate of the upper-right corner of a rectangle.
|
||||
\arg \a y1 specifies the y-coordinate of the upper-right corner of a rectangle.
|
||||
/*!
|
||||
x0 specifies the x-coordinate of the bottom-left corner of a rectangle.
|
||||
y0 specifies the y-coordinate of the bottom-left corner of a rectangle.
|
||||
x1 specifies the x-coordinate of the upper-right corner of a rectangle.
|
||||
y1 specifies the y-coordinate of the upper-right corner of a rectangle.
|
||||
*/
|
||||
template <class T>
|
||||
class DVAPI TRectT {
|
||||
|
@ -561,14 +561,18 @@ if x0==y1 && y0==y1 and rect is a TRectD then rect is empty */
|
|||
TRectT();
|
||||
|
||||
TRectT(T _x0, T _y0, T _x1, T _y1) : x0(_x0), y0(_y0), x1(_x1), y1(_y1){};
|
||||
|
||||
TRectT(const TRectT &rect)
|
||||
: x0(rect.x0), y0(rect.y0), x1(rect.x1), y1(rect.y1){};
|
||||
|
||||
TRectT(const TPointT<T> &p0, const TPointT<T> &p1) // non importa l'ordine
|
||||
: x0(std::min((T)p0.x, (T)p1.x)),
|
||||
y0(std::min((T)p0.y, (T)p1.y)),
|
||||
x1(std::max((T)p0.x, (T)p1.x)),
|
||||
y1(std::max((T)p0.y, (T)p1.y)){};
|
||||
|
||||
TRectT(const TPointT<T> &bottomLeft, const TDimensionT<T> &d);
|
||||
|
||||
TRectT(const TDimensionT<T> &d);
|
||||
|
||||
void empty();
|
||||
|
@ -588,15 +592,15 @@ TRectI is empty if x0>x1 || y0>y1 */
|
|||
TPointT<T> getP11() const { return TPointT<T>(x1, y1); };
|
||||
|
||||
//! Returns the union of two source rectangles.
|
||||
/*!The union is the smallest rectangle that contains both source rectangles.
|
||||
*/
|
||||
//!The union is the smallest rectangle that contains both source rectangles.
|
||||
TRectT<T> operator+(const TRectT<T> &rect) const { // unione
|
||||
if (isEmpty())
|
||||
return rect;
|
||||
else if (rect.isEmpty())
|
||||
return *this;
|
||||
else
|
||||
return TRectT<T>(std::min((T)x0, (T)rect.x0), std::min((T)y0, (T)rect.y0),
|
||||
return TRectT<T>(std::min((T)x0, (T)rect.x0),
|
||||
std::min((T)y0, (T)rect.y0),
|
||||
std::max((T)x1, (T)rect.x1),
|
||||
std::max((T)y1, (T)rect.y1));
|
||||
};
|
||||
|
@ -607,10 +611,8 @@ TRectI is empty if x0>x1 || y0>y1 */
|
|||
return *this = *this * rect;
|
||||
};
|
||||
|
||||
/*!Returns the intersection of two existing rectangles.
|
||||
|
||||
The intersection is the largest rectangle contained in both existing rectangles.
|
||||
*/
|
||||
//!Returns the intersection of two existing rectangles.
|
||||
//The intersection is the largest rectangle contained in both existing rectangles.
|
||||
TRectT<T> operator*(const TRectT<T> &rect) const { // intersezione
|
||||
if (isEmpty() || rect.isEmpty())
|
||||
return TRectT<T>();
|
||||
|
@ -622,7 +624,7 @@ The intersection is the largest rectangle contained in both existing rectangles.
|
|||
std::min((T)y1, (T)rect.y1));
|
||||
};
|
||||
|
||||
TRectT<T> &operator+=(const TPointT<T> &p) { // spostamento
|
||||
TRectT<T> &operator+=(const TPointT<T> &p) { // shift
|
||||
x0 += p.x;
|
||||
y0 += p.y;
|
||||
x1 += p.x;
|
||||
|
@ -691,6 +693,7 @@ template class DVAPI TRectT<double>;
|
|||
\relates TRectT
|
||||
Convert a TRectD into a TRect
|
||||
*/
|
||||
|
||||
inline TRect convert(const TRectD &r) {
|
||||
return TRect((int)(r.x0 + 0.5), (int)(r.y0 + 0.5), (int)(r.x1 + 0.5),
|
||||
(int)(r.y1 + 0.5));
|
||||
|
@ -707,8 +710,8 @@ inline TRectD convert(const TRect &r) { return TRectD(r.x0, r.y0, r.x1, r.y1); }
|
|||
\relates TPointT
|
||||
*/
|
||||
inline TRectD boundingBox(const TPointD &p0, const TPointD &p1) {
|
||||
return TRectD(std::min(p0.x, p1.x), std::min(p0.y, p1.y),
|
||||
std::max(p0.x, p1.x), std::max(p0.y, p1.y));
|
||||
return TRectD(std::min(p0.x, p1.x), std::min(p0.y, p1.y), // bottom left
|
||||
std::max(p0.x, p1.x), std::max(p0.y, p1.y)); // top right
|
||||
}
|
||||
/*!
|
||||
\relates TRectT
|
||||
|
@ -733,6 +736,7 @@ inline TRectD boundingBox(const TPointD &p0, const TPointD &p1,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// TRectT is a rectangle that uses thick points
|
||||
template <>
|
||||
inline TRectT<int>::TRectT() : x0(0), y0(0), x1(-1), y1(-1) {}
|
||||
template <>
|
||||
|
@ -754,6 +758,8 @@ inline void TRectT<int>::empty() {
|
|||
x0 = y0 = 0;
|
||||
x1 = y1 = -1;
|
||||
}
|
||||
|
||||
// Is the adding of one here to account for the thickness?
|
||||
template <>
|
||||
inline int TRectT<int>::getLx() const {
|
||||
return x1 >= x0 ? x1 - x0 + 1 : 0;
|
||||
|
@ -846,21 +852,15 @@ extern DVVAR const TRectI infiniteRectI;
|
|||
//=============================================================================
|
||||
//! This is the base class for the affine transformations.
|
||||
/*!
|
||||
This class performs basic manipulations of affine
|
||||
transformations.
|
||||
An affine transformation is a linear transformation followed by
|
||||
a translation.
|
||||
<p>
|
||||
\f$ x \mapsto \bf{A} x + b \f$
|
||||
</p>
|
||||
<p>
|
||||
\f$ \bf{A} \f$ is a \f$ 2X2 \f$ matrix.
|
||||
In a matrix notation:
|
||||
<p> \f$ \left(\begin{array}{c} \vec{y} \\ 1 \end{array}\right) =
|
||||
\left( \begin{array}{cc} \bf{A} & \vec{b} \\ \vec{0} & 1
|
||||
\end{array}\right)
|
||||
\left(\begin{array}{c}\vec{x} \\ 1 \end{array} \right) \f$ </p>
|
||||
*/
|
||||
This class performs basic manipulations of affine transformations.
|
||||
An affine transformation is a linear transformation followed by a translation.
|
||||
|
||||
[a11, a12, a13]
|
||||
[a21, a22, a23]
|
||||
|
||||
a13 and a23 represent translation (moving sideways or up and down)
|
||||
the other 4 handle rotation, scale and shear
|
||||
*/
|
||||
class DVAPI TAffine {
|
||||
public:
|
||||
double a11, a12, a13;
|
||||
|
@ -891,7 +891,7 @@ public:
|
|||
Assignment operator.
|
||||
*/
|
||||
TAffine &operator=(const TAffine &a);
|
||||
/*Sposto in tgeometry.cpp
|
||||
/*Moved to tgeometry.cpp
|
||||
{
|
||||
a11 = a.a11; a12 = a.a12; a13 = a.a13;
|
||||
a21 = a.a21; a22 = a.a22; a23 = a.a23;
|
||||
|
@ -905,7 +905,7 @@ return *this;
|
|||
|
||||
*/
|
||||
TAffine operator*(const TAffine &b) const;
|
||||
/*Sposto in tgeometry.cpp
|
||||
/*Moved to in tgeometry.cpp
|
||||
{
|
||||
return TAffine (
|
||||
a11 * b.a11 + a12 * b.a21,
|
||||
|
@ -919,7 +919,7 @@ a21 * b.a13 + a22 * b.a23 + a23);
|
|||
*/
|
||||
|
||||
TAffine operator*=(const TAffine &b);
|
||||
/*Sposto in tgeometry.cpp
|
||||
/*Moved to tgeometry.cpp
|
||||
{
|
||||
return *this = *this * b;
|
||||
};
|
||||
|
@ -930,7 +930,7 @@ return *this = *this * b;
|
|||
*/
|
||||
|
||||
TAffine inv() const;
|
||||
/*Sposto in tgeometry.cpp
|
||||
/*Moved to tgeometry.cpp
|
||||
{
|
||||
if(a12 == 0.0 && a21 == 0.0)
|
||||
{
|
||||
|
|
|
@ -18,12 +18,7 @@
|
|||
#endif
|
||||
|
||||
//******************** IK Utility *********************
|
||||
//
|
||||
// Di seguito le classi VectorRn e MatrixRmn
|
||||
// TODO: Se possibile cambiare e usare le STL
|
||||
//
|
||||
//
|
||||
//****************************************************
|
||||
//*****************************************************
|
||||
|
||||
//***********************************************************************
|
||||
// CLASS VectorRN
|
||||
|
@ -683,15 +678,15 @@ public:
|
|||
void Reset();
|
||||
|
||||
private:
|
||||
IKSkeleton *skeleton; // skeletro associato a questa matrice Jacobiana
|
||||
IKSkeleton *skeleton; // skeleton associated with this Jacobian matrix
|
||||
std::vector<TPointD> target;
|
||||
int nEffector; // Numero di end effectors
|
||||
int nJoint; // Numero di Joints
|
||||
int nRow; // righe matrice J (= 2*numero di end effectors)
|
||||
int nCol; // numero di colonne di J
|
||||
int nEffector; // Number of end effectors
|
||||
int nJoint; // Number of Joints
|
||||
int nRow; // matrix rows J(= 2 * number of end effectors)
|
||||
int nCol; // number of columns of J
|
||||
|
||||
MatrixRmn
|
||||
Jend; // matrice Jacobiana basata sulle posizioni degli end effectors
|
||||
Jend; // Jacobian matrix based on the positions of the end effectors
|
||||
MatrixRmn Jtarget;
|
||||
MatrixRmn Jnorms; // Norms of 2-vectors in active Jacobian (solo SDLS)
|
||||
|
||||
|
@ -709,10 +704,10 @@ private:
|
|||
|
||||
VectorRn dPreTheta; // (vale solo per SDLS)
|
||||
|
||||
// Parametri per pseudorinversa
|
||||
// Parameters for pseudorinverse
|
||||
static const double PseudoInverseThresholdFactor;
|
||||
|
||||
// Paremetri pe il metodo Damped Least Squares
|
||||
// Paremeters for the Damped Least Squares method
|
||||
static const double DefaultDampingLambda;
|
||||
double DampingLambda;
|
||||
double DampingLambdaSq;
|
||||
|
|
|
@ -22,8 +22,8 @@ public:
|
|||
enum Purpose { JOINT, EFFECTOR };
|
||||
|
||||
IKNode() : m_parent(0), m_pos() {
|
||||
r = TPointD(0.0, 1.0); // r sara' aggiornato quando il nodo sara; inserito
|
||||
// nello skeleton
|
||||
r = TPointD(0.0, 1.0); // r will be updated when the node is added
|
||||
// in the skeleton
|
||||
theta = 0.0;
|
||||
m_parent = 0;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
}
|
||||
|
||||
bool isFrozen() const { return freezed; }
|
||||
void freeze() { freezed = true; } // mantiene l'angolo theta costante
|
||||
void freeze() { freezed = true; } // keeps the theta angle constant
|
||||
void unFreeze() { freezed = false; }
|
||||
|
||||
private:
|
||||
|
@ -79,20 +79,20 @@ private:
|
|||
|
||||
TPointD m_pos;
|
||||
Purpose m_purpose;
|
||||
int m_seqNumJoint; // indice del Joint nella sequenza di Joint
|
||||
int m_seqNumEffector; // indice dell'Effector nella sequenza di Effectors
|
||||
int m_seqNumJoint; // Joint index in the Joint sequence
|
||||
int m_seqNumEffector; // index of the effector in the sequence of effectors
|
||||
|
||||
TPointD r; // Posizione relativa
|
||||
TPointD s; // Posizione Globale
|
||||
// TPointD w; // Rotazione Globale dell'asse
|
||||
TPointD r; // Relative position
|
||||
TPointD s; // Global position
|
||||
// TPointD w; // Global axis rotation
|
||||
|
||||
double theta; // angolo del joint (radianti)
|
||||
double theta0; // angolo iniziale del joint (radianti)
|
||||
double minTheta; // limite inferiore angolo
|
||||
double maxTheta; // limite superiore angolo
|
||||
double restAngle; // angolo esplementare
|
||||
double theta; // joint angle(radians)
|
||||
double theta0; // initial angle of the joint(radians)
|
||||
double minTheta; // lower angle limit
|
||||
double maxTheta; // high angle limit
|
||||
double restAngle;
|
||||
|
||||
bool freezed; // Se vero l'angolo è blocccato
|
||||
bool freezed;
|
||||
};
|
||||
|
||||
#endif // IKNODE_H
|
||||
|
|
|
@ -181,6 +181,7 @@ DragPositionTool::DragPositionTool(SkeletonTool *tool)
|
|||
void DragPositionTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
|
||||
start();
|
||||
m_firstPos = pos;
|
||||
m_firstDrag = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
@ -188,6 +189,11 @@ void DragPositionTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
|
|||
void DragPositionTool::leftButtonDrag(const TPointD &pos,
|
||||
const TMouseEvent &e) {
|
||||
TPointD delta = pos - m_firstPos;
|
||||
if (m_firstDrag && (delta.x > 2.0 || delta.y > 2.0)) {
|
||||
m_firstPos = pos;
|
||||
delta = TPointD(0.0, 0.0);
|
||||
m_firstDrag = false;
|
||||
}
|
||||
if (e.isShiftPressed()) {
|
||||
if (fabs(delta.x) > fabs(delta.y))
|
||||
delta.y = 0;
|
||||
|
@ -419,12 +425,21 @@ void ParentChangeTool::draw() { getTool()->drawHooks(); }
|
|||
//
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
// This needs some clarification.
|
||||
namespace {
|
||||
class Graph {
|
||||
|
||||
// local variables defined below are:
|
||||
// Nodes m_nodes;
|
||||
// std::map<int, int> m_leaves;
|
||||
|
||||
|
||||
public:
|
||||
typedef std::set<int> Links;
|
||||
typedef Links::const_iterator LinkIter;
|
||||
|
||||
// the second part of the nodes map is a set if ints
|
||||
typedef std::map<int, Links> Nodes;
|
||||
typedef Nodes::const_iterator NodeIter;
|
||||
typedef std::map<int, int> LeaveTable;
|
||||
|
@ -433,11 +448,16 @@ public:
|
|||
Graph() {}
|
||||
|
||||
int touch(int id) {
|
||||
// insert an empty node if not found
|
||||
if (m_nodes.count(id) == 0) m_nodes[id] = Links();
|
||||
return id;
|
||||
}
|
||||
|
||||
// check if a node is found in m_nodes
|
||||
bool isNode(int id) const { return m_nodes.count(id) > 0; }
|
||||
|
||||
int getNodeCount() const { return (int)m_nodes.size(); }
|
||||
|
||||
void link(int a, int b) {
|
||||
touch(a);
|
||||
touch(b);
|
||||
|
@ -448,12 +468,15 @@ public:
|
|||
NodeIter it = m_nodes.find(a);
|
||||
return it == m_nodes.end() ? false : it->second.count(b);
|
||||
}
|
||||
|
||||
const Links &getLinks(int id) const {
|
||||
static const Links empty;
|
||||
NodeIter it = m_nodes.find(id);
|
||||
return it == m_nodes.end() ? empty : it->second;
|
||||
}
|
||||
|
||||
int getLinkCount(int id) const { return (int)getLinks(id).size(); }
|
||||
|
||||
int getFirstLink(int id) const {
|
||||
const Links &links = getLinks(id);
|
||||
return links.empty() ? -1 : *(links.begin());
|
||||
|
@ -462,6 +485,9 @@ public:
|
|||
NodeIter begin() const { return m_nodes.begin(); }
|
||||
NodeIter end() const { return m_nodes.end(); }
|
||||
|
||||
// Wht is a leave?
|
||||
// m_leaves is a std map of int int
|
||||
|
||||
bool isLeave(int id) const { return m_leaves.count(id); }
|
||||
|
||||
enum LeaveType {
|
||||
|
@ -470,14 +496,20 @@ public:
|
|||
CHILD_END = 0x4,
|
||||
PARENT_END = 0x8
|
||||
};
|
||||
|
||||
int getLeaveType(int id) const {
|
||||
LeaveIter it = m_leaves.find(id);
|
||||
return it == m_leaves.end() ? 0 : it->second;
|
||||
}
|
||||
|
||||
void setLeaveType(int id, int type) { m_leaves[id] = type; }
|
||||
|
||||
|
||||
// This gets rid of a node.
|
||||
void remove(int id) {
|
||||
NodeIter it = m_nodes.find(id);
|
||||
if (it != m_nodes.end()) {
|
||||
// iterate over the links
|
||||
for (LinkIter j = it->second.begin(); j != it->second.end(); ++j)
|
||||
m_nodes[*j].erase(id);
|
||||
m_nodes.erase(it->first);
|
||||
|
@ -499,15 +531,21 @@ bool hasPinned(const Skeleton::Bone *bone, const Skeleton::Bone *prevBone) {
|
|||
if (!bone) return false;
|
||||
bool isHandle = prevBone == 0;
|
||||
bool isChild = prevBone != 0 && prevBone == bone->getParent();
|
||||
|
||||
if (bone->getPinnedStatus() != Skeleton::Bone::FREE) return true;
|
||||
|
||||
if (bone->getParent() && bone->getParent() != prevBone &&
|
||||
hasPinned(bone->getParent(), bone))
|
||||
return true;
|
||||
hasPinned(bone->getParent(), bone)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bone->getChildCount(); i++)
|
||||
if (bone->getChild(i) != prevBone)
|
||||
if (hasPinned(bone->getChild(i), bone)) return true;
|
||||
for (int i = 0; i < bone->getChildCount(); i++) {
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
if (hasPinned(bone->getChild(i), bone)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -518,7 +556,10 @@ bool hasPinned(const Skeleton::Bone *bone, const Skeleton::Bone *prevBone) {
|
|||
bool addToActiveChain(Graph &tree, const Skeleton::Bone *bone,
|
||||
const Skeleton::Bone *prevBone) {
|
||||
if (!bone) return false;
|
||||
|
||||
// The handle is what you grabbed
|
||||
bool isHandle = prevBone == 0;
|
||||
|
||||
bool isChild = prevBone != 0 && prevBone == bone->getParent();
|
||||
bool isParent = prevBone != 0 && prevBone->getParent() == bone;
|
||||
int pinnedStatus = bone->getPinnedStatus();
|
||||
|
@ -527,22 +568,33 @@ bool addToActiveChain(Graph &tree, const Skeleton::Bone *bone,
|
|||
bool isTempPinned = pinnedStatus == Skeleton::Bone::TEMP_PINNED;
|
||||
|
||||
bool propagate = false;
|
||||
if (!isChild && isFree)
|
||||
if (bone->getParent())
|
||||
propagate |= addToActiveChain(tree, bone->getParent(), bone);
|
||||
|
||||
// Go up the chain from what you grabbed and add bones
|
||||
if (!isChild && isFree) {
|
||||
if (bone->getParent()) {
|
||||
propagate |= addToActiveChain(tree, bone->getParent(), bone);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> children;
|
||||
if (isHandle || isFree)
|
||||
for (int i = 0; i < bone->getChildCount(); i++)
|
||||
if (bone->getChild(i) != prevBone)
|
||||
propagate |= addToActiveChain(tree, bone->getChild(i), bone);
|
||||
// Once you reach the top parent, add the other children
|
||||
if (isHandle || isFree) {
|
||||
for (int i = 0; i < bone->getChildCount(); i++) {
|
||||
if (bone->getChild(i) != prevBone) {
|
||||
propagate |= addToActiveChain(tree, bone->getChild(i), bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool insert = false;
|
||||
|
||||
if (isHandle) // the handle must be added anyway
|
||||
insert = true;
|
||||
|
||||
else if (isChild) // add child if it's pinned or if some gran-child has been
|
||||
// added
|
||||
insert = !isFree || propagate;
|
||||
|
||||
else if (isTempPinned) {
|
||||
// parent temp pinned are normally added, but if another branch is pinned we
|
||||
// are not
|
||||
|
@ -656,6 +708,7 @@ public:
|
|||
TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
|
||||
TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
|
||||
}
|
||||
|
||||
void redo() const override {
|
||||
TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
|
||||
for (int i = 0; i < (int)m_nodes.size(); i++) {
|
||||
|
@ -689,7 +742,7 @@ IKTool::IKTool(SkeletonTool *tool, TTool::Viewer *viewer, Skeleton *skeleton,
|
|||
, m_pos()
|
||||
, m_columnIndex(columnIndex)
|
||||
, m_valid(false)
|
||||
, m_IHateIK(false)
|
||||
, m_frameOnNewPin(false)
|
||||
, m_foot(0)
|
||||
, m_firstFoot(0)
|
||||
, m_undo(0) {}
|
||||
|
@ -708,14 +761,13 @@ bool IKTool::isParentOf(int columnIndex, int childColumnIndex) const {
|
|||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
// This is a beast.
|
||||
|
||||
void IKTool::initEngine(const TPointD &pos) {
|
||||
m_valid = false;
|
||||
m_engine.clear();
|
||||
m_joints.clear();
|
||||
|
||||
// m_skeleton->getRootBone()->getStageObject()->setStatus(TStageObject::IK);
|
||||
|
||||
// build the active chain (bounded by m_columnIndex and pinned nodes)
|
||||
Graph chain;
|
||||
addToActiveChain(chain, m_skeleton->getBoneByColumnIndex(m_columnIndex), 0);
|
||||
|
@ -739,8 +791,7 @@ void IKTool::initEngine(const TPointD &pos) {
|
|||
}
|
||||
|
||||
// search the foot (i.e. the pinned node). if there are no pinned node find
|
||||
// the first
|
||||
// temp-pinned
|
||||
// the first temp-pinned
|
||||
int foot = -1;
|
||||
for (Graph::NodeIter it = chain.begin(); it != chain.end(); ++it)
|
||||
if (chain.isLeave(it->first)) {
|
||||
|
@ -763,8 +814,7 @@ void IKTool::initEngine(const TPointD &pos) {
|
|||
}
|
||||
|
||||
// if the handle is a terminal node (i.e. just one link) and the next node is
|
||||
// a child
|
||||
// move the handle to the next node
|
||||
// a child move the handle to the next node
|
||||
int handle = m_columnIndex;
|
||||
if (chain.getLinkCount(handle) == 1) {
|
||||
int nextNode = chain.getFirstLink(handle);
|
||||
|
@ -774,8 +824,6 @@ void IKTool::initEngine(const TPointD &pos) {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// "reverse" the tree to suit the IKEngine convention
|
||||
std::vector<std::pair<int, Skeleton::Bone *>> stack;
|
||||
std::vector<int> done;
|
||||
|
@ -858,7 +906,11 @@ void IKTool::initEngine(const TPointD &pos) {
|
|||
|
||||
//------------------------------------------------------------
|
||||
|
||||
// TODO cambiare questo nome; aggiungere due righe di spiegazione
|
||||
// This sets foot placement data
|
||||
// and checks if the current frame is the start
|
||||
// of a new pinned center
|
||||
// The name of this function should be changed once it
|
||||
// actually works. Until then, the name is fitting.
|
||||
void IKTool::computeIHateIK() {
|
||||
std::vector<TStageObject *> objs;
|
||||
for (int i = 0; i < m_skeleton->getBoneCount(); i++)
|
||||
|
@ -866,24 +918,30 @@ void IKTool::computeIHateIK() {
|
|||
int n = (int)objs.size();
|
||||
int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
|
||||
m_foot = m_firstFoot = 0;
|
||||
m_IHateIK = false;
|
||||
m_frameOnNewPin = false;
|
||||
|
||||
// this just finds the first pin
|
||||
int i;
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(frame); i++) {
|
||||
}
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(frame); i++) {}
|
||||
if (i == n) return;
|
||||
|
||||
// this makes m_foot to be the current pin
|
||||
m_foot = objs[i];
|
||||
|
||||
// check to see if this frame is the start of a new pin
|
||||
const TPinnedRangeSet::Range *range =
|
||||
m_foot->getPinnedRangeSet()->getRange(frame);
|
||||
if (!range || range->first != frame) return;
|
||||
|
||||
m_IHateIK = true;
|
||||
m_frameOnNewPin = true;
|
||||
int firstFrame = frame - 1;
|
||||
m_firstFoot = m_foot;
|
||||
|
||||
// the frame is the start of a new pinned frame, find the previous pin
|
||||
for (;;) {
|
||||
for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(firstFrame);
|
||||
i++) {
|
||||
}
|
||||
i++) {}
|
||||
|
||||
if (i == n) break;
|
||||
m_firstFoot = objs[i];
|
||||
range = m_firstFoot->getPinnedRangeSet()->getRange(firstFrame);
|
||||
|
@ -891,6 +949,7 @@ void IKTool::computeIHateIK() {
|
|||
firstFrame = range->first - 1;
|
||||
if (firstFrame < 0) break;
|
||||
}
|
||||
|
||||
m_footPlacement = m_foot->getPlacement(frame);
|
||||
m_firstFootPlacement = m_firstFoot->getPinnedRangeSet()->getPlacement();
|
||||
}
|
||||
|
@ -934,7 +993,7 @@ void IKTool::storeOldValues() {
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
// This is called on movement of the mouse with button down
|
||||
void IKTool::apply() {
|
||||
if (!m_valid) return;
|
||||
TStageObject *rootObj = m_skeleton->getRootBone()->getStageObject();
|
||||
|
@ -943,7 +1002,7 @@ void IKTool::apply() {
|
|||
for (int i = 0; i < (int)m_joints.size(); i++)
|
||||
m_undo->addNode(m_joints[i].m_bone->getStageObject()->getId());
|
||||
|
||||
if (m_IHateIK && m_firstFoot) {
|
||||
if (m_frameOnNewPin && m_firstFoot) {
|
||||
m_undo->setFirstFootId(m_firstFoot->getId());
|
||||
m_undo->setFirstFootOldPlacement(
|
||||
m_firstFoot->getPinnedRangeSet()->getPlacement());
|
||||
|
@ -963,7 +1022,7 @@ void IKTool::apply() {
|
|||
param->setValue(frame, theta);
|
||||
}
|
||||
m_skeleton->getRootBone()->getStageObject()->invalidate();
|
||||
if (m_IHateIK) {
|
||||
if (m_frameOnNewPin) {
|
||||
TStageObject *rootObj = m_skeleton->getRootBone()->getStageObject();
|
||||
rootObj->setStatus(TStageObject::XY);
|
||||
rootObj->invalidate();
|
||||
|
@ -1012,7 +1071,7 @@ void IKTool::leftButtonDrag(const TPointD &p, const TMouseEvent &e) {
|
|||
|
||||
void IKTool::leftButtonUp(const TPointD &p, const TMouseEvent &e) {
|
||||
if (m_undo) {
|
||||
if (m_IHateIK && m_firstFoot)
|
||||
if (m_frameOnNewPin && m_firstFoot)
|
||||
m_undo->setFirstFootNewPlacement(
|
||||
m_firstFoot->getPinnedRangeSet()->getPlacement());
|
||||
TUndoManager::manager()->add(m_undo);
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
|
||||
class DragPositionTool final : public DragChannelTool {
|
||||
TPointD m_firstPos;
|
||||
bool m_firstDrag = false;
|
||||
|
||||
public:
|
||||
DragPositionTool(SkeletonTool *tool);
|
||||
|
@ -161,9 +162,10 @@ class IKTool final : public DragTool {
|
|||
int m_columnIndex;
|
||||
IKEngine m_engine;
|
||||
bool m_valid;
|
||||
bool m_rootInvolved;
|
||||
TAffine m_footPlacement, m_firstFootPlacement;
|
||||
TStageObject *m_foot, *m_firstFoot;
|
||||
bool m_IHateIK;
|
||||
bool m_frameOnNewPin;
|
||||
IKToolUndo *m_undo;
|
||||
|
||||
struct Joint {
|
||||
|
|
|
@ -78,7 +78,7 @@ inline std::string removeTrailingH(std::string handle) {
|
|||
//
|
||||
//------------------------------------------------------------
|
||||
|
||||
// return true iff column ancestorIndex is column descentIndex or its parent or
|
||||
// return true if column ancestorIndex is column descentIndex or its parent or
|
||||
// the parent of the parent, etc.
|
||||
static bool isAncestorOf(int ancestorIndex, int descendentIndex) {
|
||||
TStageObjectId ancestorId = TStageObjectId::ColumnId(ancestorIndex);
|
||||
|
@ -93,7 +93,7 @@ static bool isAncestorOf(int ancestorIndex, int descendentIndex) {
|
|||
|
||||
static void getHooks(std::vector<HookData> &hooks, TXsheet *xsh, int row,
|
||||
int col, TPointD dpiScale) {
|
||||
// nota. hook position is in the coordinate system of the parent object.
|
||||
// note. hook position is in the coordinate system of the parent object.
|
||||
// a inch is Stage::inch
|
||||
|
||||
TXshCell cell = xsh->getCell(row, col);
|
||||
|
@ -342,7 +342,7 @@ void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
|
|||
|
||||
int selectedDevice = pick(e.m_pos);
|
||||
|
||||
// cambio drawing
|
||||
// change drawing
|
||||
if (selectedDevice == TD_ChangeDrawing ||
|
||||
selectedDevice == TD_IncrementDrawing ||
|
||||
selectedDevice == TD_DecrementDrawing) {
|
||||
|
@ -356,7 +356,7 @@ void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
|
|||
return;
|
||||
}
|
||||
|
||||
// click su un hook: attacca la colonna corrente tramite quell'hook
|
||||
// click on a hook: attach the current column via that hook
|
||||
if (TD_Hook <= selectedDevice && selectedDevice < TD_Hook + 50) {
|
||||
TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
|
||||
TStageObjectId objId = TStageObjectId::ColumnId(currentColumnIndex);
|
||||
|
@ -381,7 +381,7 @@ void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
|
|||
bool justSelected = false;
|
||||
|
||||
if (m_device < 0) {
|
||||
// nessun gadget cliccato. Eventualmente seleziono la colonna
|
||||
// No gadget clicked. Select the column
|
||||
std::vector<int> columnIndexes;
|
||||
getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, getPixelSize() * 5,
|
||||
false);
|
||||
|
@ -414,12 +414,21 @@ void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) {
|
|||
|
||||
// lock/unlock: modalita IK
|
||||
if (TD_LockStageObject <= m_device && m_device < TD_LockStageObject + 1000) {
|
||||
Skeleton* skeleton = new Skeleton();
|
||||
buildSkeleton(*skeleton, currentColumnIndex);
|
||||
int columnIndex = m_device - TD_LockStageObject;
|
||||
int frame = app->getCurrentFrame()->getFrame();
|
||||
togglePinnedStatus(columnIndex, frame, e.isShiftPressed());
|
||||
invalidate();
|
||||
m_dragTool = 0;
|
||||
return;
|
||||
int frame = app->getCurrentFrame()->getFrame();
|
||||
if (skeleton->getBoneByColumnIndex(columnIndex) == skeleton->getRootBone()) {
|
||||
app->getCurrentColumn()->setColumnIndex(columnIndex);
|
||||
m_device = TD_Translation;
|
||||
}
|
||||
else if (e.isShiftPressed()) {
|
||||
togglePinnedStatus(columnIndex, frame, e.isShiftPressed());
|
||||
invalidate();
|
||||
m_dragTool = 0;
|
||||
return;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
switch (m_device) {
|
||||
|
@ -989,7 +998,7 @@ void SkeletonTool::drawIKBone(const TPointD &a, const TPointD &b) {
|
|||
//-------------------------------------------------------------------
|
||||
|
||||
void SkeletonTool::computeMagicLinks() {
|
||||
// TODO: spostare qui il calcolo dei magic link
|
||||
// TODO: move the calculation of the magic links here
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
|
|
@ -18,7 +18,7 @@ int IKEngine::addJoint(const TPointD &pos, int indexParent) {
|
|||
m_skeleton.setParent(index, indexParent);
|
||||
return index;
|
||||
}
|
||||
// la root deve coincidere con un punto bloccato!
|
||||
// The root must be a pinned point!
|
||||
void IKEngine::setRoot(const TPointD &pos) {
|
||||
m_skeleton.addNode(new IKNode());
|
||||
m_skeleton.setNode(0, pos, IKNode::JOINT);
|
||||
|
@ -64,7 +64,7 @@ void IKEngine::drag(TPointD &pos) {
|
|||
// se lo scheletro è vuoto non succede nulla
|
||||
if (m_skeleton.getNodeCount() == 0) return;
|
||||
|
||||
// afferro l'ultimo punto della catena
|
||||
// Grab the last point of the chain
|
||||
int indexDrag = m_skeleton.getNodeCount() - 1;
|
||||
if (m_skeleton.getNode(indexDrag)->getParent()->IsEffector()) return;
|
||||
m_skeleton.setPurpose(indexDrag, IKNode::EFFECTOR);
|
||||
|
|
Loading…
Reference in a new issue