| |
| |
| #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; |
| } |
| |
| } |
| |
| |
| |
| 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<int> &tempPinnedColumns) |
| { |
| |
| m_rootBone = 0; |
| clearPointerContainer(m_bones); |
| |
| |
| TStageObjectId ancestorId = getAncestor(xsh, TStageObjectId::ColumnId(col)); |
| |
| |
| std::map<TStageObjectId, Bone *> 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 (pinnedCount == 0 && m_rootBone) |
| m_rootBone->setPinnedStatus(Bone::PINNED); |
| |
| |
| if (boneTable.empty()) { |
| assert(!m_rootBone); |
| return; |
| } |
| |
| |
| std::map<TStageObjectId, Bone *>::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); |
| } |
| |
| |
| 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(); |
| } |
| } |
| |