diff --git a/toonz/sources/include/tgeometry.h b/toonz/sources/include/tgeometry.h index f5653a7..af418cd 100644 --- a/toonz/sources/include/tgeometry.h +++ b/toonz/sources/include/tgeometry.h @@ -65,7 +65,7 @@ public: \sa rotate270 */ template -inline TPointT rotate90(const TPointT &p) // counterclockwise +inline TPointT rotate90(const TPointT &p) // 90 counterclockwise { return TPointT(-p.y, p.x); } @@ -76,7 +76,7 @@ inline TPointT rotate90(const TPointT &p) // counterclockwise \sa rotate90 */ template -inline TPointT rotate270(const TPointT &p) // clockwise +inline TPointT rotate270(const TPointT &p) // 90 clockwise { return TPointT(p.y, -p.x); } @@ -84,7 +84,7 @@ inline TPointT rotate270(const TPointT &p) // clockwise /*! \relates TPointT */ -template // prodotto scalare +template // Scalar(dot) Product inline T operator*(const TPointT &a, const TPointT &b) { return a.x * b.x + a.y * b.y; } @@ -542,11 +542,11 @@ template class DVAPI TDimensionT; //============================================================================= //! 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 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 &p0, const TPointT &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 &bottomLeft, const TDimensionT &d); + TRectT(const TDimensionT &d); void empty(); @@ -588,15 +592,15 @@ TRectI is empty if x0>x1 || y0>y1 */ TPointT getP11() const { return TPointT(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 operator+(const TRectT &rect) const { // unione if (isEmpty()) return rect; else if (rect.isEmpty()) return *this; else - return TRectT(std::min((T)x0, (T)rect.x0), std::min((T)y0, (T)rect.y0), + return TRectT(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 operator*(const TRectT &rect) const { // intersezione if (isEmpty() || rect.isEmpty()) return TRectT(); @@ -622,7 +624,7 @@ The intersection is the largest rectangle contained in both existing rectangles. std::min((T)y1, (T)rect.y1)); }; - TRectT &operator+=(const TPointT &p) { // spostamento + TRectT &operator+=(const TPointT &p) { // shift x0 += p.x; y0 += p.y; x1 += p.x; @@ -691,6 +693,7 @@ template class DVAPI TRectT; \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::TRectT() : x0(0), y0(0), x1(-1), y1(-1) {} template <> @@ -754,6 +758,8 @@ inline void TRectT::empty() { x0 = y0 = 0; x1 = y1 = -1; } + +// Is the adding of one here to account for the thickness? template <> inline int TRectT::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. -

- \f$ x \mapsto \bf{A} x + b \f$ -

-

- \f$ \bf{A} \f$ is a \f$ 2X2 \f$ matrix. - In a matrix notation: -

\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$

- */ + 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) { diff --git a/toonz/sources/include/toonz/ikjacobian.h b/toonz/sources/include/toonz/ikjacobian.h index 3fda54a..7151dca 100644 --- a/toonz/sources/include/toonz/ikjacobian.h +++ b/toonz/sources/include/toonz/ikjacobian.h @@ -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 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; diff --git a/toonz/sources/include/toonz/iknode.h b/toonz/sources/include/toonz/iknode.h index 20feea7..923a11b 100644 --- a/toonz/sources/include/toonz/iknode.h +++ b/toonz/sources/include/toonz/iknode.h @@ -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 diff --git a/toonz/sources/tnztools/skeletonsubtools.cpp b/toonz/sources/tnztools/skeletonsubtools.cpp index b6f3a90..3ca95f6 100644 --- a/toonz/sources/tnztools/skeletonsubtools.cpp +++ b/toonz/sources/tnztools/skeletonsubtools.cpp @@ -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 m_leaves; + + public: typedef std::set Links; typedef Links::const_iterator LinkIter; + + // the second part of the nodes map is a set if ints typedef std::map Nodes; typedef Nodes::const_iterator NodeIter; typedef std::map 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 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> stack; std::vector 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 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); diff --git a/toonz/sources/tnztools/skeletonsubtools.h b/toonz/sources/tnztools/skeletonsubtools.h index 724bf59..f3eb6ac 100644 --- a/toonz/sources/tnztools/skeletonsubtools.h +++ b/toonz/sources/tnztools/skeletonsubtools.h @@ -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 { diff --git a/toonz/sources/tnztools/skeletontool.cpp b/toonz/sources/tnztools/skeletontool.cpp index 8084a0b..0cb31d2 100644 --- a/toonz/sources/tnztools/skeletontool.cpp +++ b/toonz/sources/tnztools/skeletontool.cpp @@ -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 &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 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 } //------------------------------------------------------------------- diff --git a/toonz/sources/toonzlib/ikengine.cpp b/toonz/sources/toonzlib/ikengine.cpp index b6ed9a0..a89005b 100644 --- a/toonz/sources/toonzlib/ikengine.cpp +++ b/toonz/sources/toonzlib/ikengine.cpp @@ -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);