#include "toonz/skeleton.h" #include "toonz/tstageobject.h" #include "toonz/tpinnedrangeset.h" #include "toonz/tstageobjectkeyframe.h" #include "toonz/txsheet.h" #include "toonz/stage.h" namespace { TStageObjectId getAncestor(TXsheet *xsh, TStageObjectId id) { assert(id.isColumn()); TStageObjectId parentId; while (parentId = xsh->getStageObjectParent(id), parentId.isColumn()) id = parentId; return id; } } // namespace //============================================================================= int Skeleton::Bone::getColumnIndex() const { return m_stageObject->getId().getIndex(); } //----------------------------------------------------------------------------- void Skeleton::Bone::setParent(Bone *parent) { if (m_parent != parent) { m_parent = parent; parent->m_children.push_back(this); } } //============================================================================= Skeleton::Skeleton() : m_rootBone(0) {} //----------------------------------------------------------------------------- Skeleton::~Skeleton() { clearPointerContainer(m_bones); } //----------------------------------------------------------------------------- void Skeleton::clear() { clearPointerContainer(m_bones); m_rootBone = 0; } //----------------------------------------------------------------------------- void Skeleton::build(TXsheet *xsh, int row, int col, const std::set &tempPinnedColumns) { // clear m_rootBone = 0; clearPointerContainer(m_bones); // antenato (colonna) della colonna corrente TStageObjectId ancestorId = getAncestor(xsh, TStageObjectId::ColumnId(col)); // costruisco le "ossa" std::map boneTable; int columnCount = xsh->getColumnCount(); int pinnedCount = 0; for (int i = 0; i < columnCount; i++) { TStageObjectId columnId(TStageObjectId::ColumnId(i)); if (getAncestor(xsh, columnId) != ancestorId) continue; TAffine aff = xsh->getPlacement(columnId, row); TPointD center = Stage::inch * xsh->getCenter(columnId, row); TPointD p = aff * center; TStageObject *obj = xsh->getStageObject(columnId); Bone *bone = new Bone(obj, p); boneTable[columnId] = bone; m_bones.push_back(bone); if (columnId == ancestorId) m_rootBone = bone; if (obj->getPinnedRangeSet()->isPinned(row)) { pinnedCount++; bone->setPinnedStatus(Bone::PINNED); } else if (tempPinnedColumns.count(i) > 0) bone->setPinnedStatus(Bone::TEMP_PINNED); } // if no bone is pinned then the root is considered pinned if (pinnedCount == 0 && m_rootBone) m_rootBone->setPinnedStatus(Bone::PINNED); // The skeleton could possibly be empty if (boneTable.empty()) { assert(!m_rootBone); return; } // assign parents std::map::iterator it, sit; for (it = boneTable.begin(); it != boneTable.end(); ++it) { sit = boneTable.find(xsh->getStageObjectParent(it->first)); if (sit != boneTable.end()) it->second->setParent(sit->second); } // select the "active chain", i.e. the starting bone (columnIndex=col) and the // ancestors it = boneTable.find(TStageObjectId::ColumnId(col)); if (it != boneTable.end()) { Bone *bone = it->second; while (bone) { bone->select(); bone = bone->getParent(); } } } //----------------------------------------------------------------------------- Skeleton::Bone *Skeleton::getBone(int index) const { assert(0 <= index && index < (int)m_bones.size()); return m_bones[index]; } //----------------------------------------------------------------------------- Skeleton::Bone *Skeleton::getBoneByColumnIndex(int columnIndex) const { for (int i = 0; i < (int)m_bones.size(); i++) if (m_bones[i]->getColumnIndex() == columnIndex) return m_bones[i]; return 0; } //----------------------------------------------------------------------------- bool Skeleton::isIKEnabled() const { return m_rootBone && m_rootBone->getStageObject()->getStatus() == TStageObject::IK; } //----------------------------------------------------------------------------- bool Skeleton::hasPinnedRanges() const { for (int i = 0; i < getBoneCount(); i++) { TStageObject *obj = getBone(i)->getStageObject(); if (obj->getPinnedRangeSet()->getRangeCount() > 0) return true; } return false; } //----------------------------------------------------------------------------- void Skeleton::clearAllPinnedRanges() { for (int i = 0; i < getBoneCount(); i++) { TStageObject *obj = getBone(i)->getStageObject(); obj->getPinnedRangeSet()->removeAllRanges(); obj->invalidate(); } }