| |
| |
|
|
| #include "tstream.h" |
| |
| |
| #include "tdoublekeyframe.h" |
| #include "tparamchange.h" |
| |
| |
| #include "ext/plasticskeleton.h" |
| #include "ext/plasticdeformerstorage.h" |
| |
| |
| #include "tcg/tcg_misc.h" |
| #include "tcg/tcg_function_types.h" |
| |
| |
| #include <memory> |
| #include <set> |
| #include <map> |
| |
| |
| #include <boost/bimap.hpp> |
| #include <boost/multi_index_container.hpp> |
| #include <boost/multi_index/ordered_index.hpp> |
| #include <boost/multi_index/member.hpp> |
| #include <boost/iterator/transform_iterator.hpp> |
| |
| #include "ext/plasticskeletondeformation.h" |
| |
| PERSIST_IDENTIFIER(PlasticSkeletonVertexDeformation, "PlasticSkeletonVertexDeformation") |
| PERSIST_IDENTIFIER(PlasticSkeletonDeformation, "PlasticSkeletonDeformation") |
| |
| DEFINE_CLASS_CODE(PlasticSkeletonDeformation, 121) |
| |
| |
| |
| |
| |
| using namespace boost::multi_index; |
| |
| namespace |
| { |
| |
| typedef boost::bimap<int, PlasticSkeletonP> SkeletonSet; |
| |
| |
| |
| struct VDKey { |
| QString m_name; |
| int m_hookNumber; |
| |
| mutable std::map<int, int> m_vIndices; |
| mutable SkVD m_vd; |
| }; |
| |
| |
| |
| typedef boost::multi_index_container<VDKey, indexed_by< |
| |
| ordered_unique<tag<QString>, member<VDKey, QString, &VDKey::m_name>>, |
| ordered_unique<tag<int>, member<VDKey, int, &VDKey::m_hookNumber>> |
| |
| >> SkVDSet; |
| |
| |
| |
| typedef SkVDSet::index<int>::type SkVDByHookNumber; |
| |
| } |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| static const char *parNames[SkVD::PARAMS_COUNT] = {"Angle", "Distance", "SO"}; |
| static const char *parMeasures[SkVD::PARAMS_COUNT] = {"angle", "fxLength", ""}; |
| |
| |
| |
| |
| double buildAngle(const PlasticSkeleton &skeleton, int v) |
| { |
| const PlasticSkeletonVertex &vx = skeleton.vertex(v); |
| int vParent = vx.parent(); |
| |
| assert(vx.parent() >= 0); |
| |
| const PlasticSkeletonVertex &vxParent = skeleton.vertex(vParent); |
| int vGrandParent = vxParent.parent(); |
| |
| |
| TPointD dir(1.0, 0.0); |
| if (vGrandParent >= 0) { |
| |
| const PlasticSkeletonVertex &vxGrandParent = skeleton.vertex(vGrandParent); |
| dir = vxParent.P() - vxGrandParent.P(); |
| } |
| |
| return tcg::point_ops::angle(dir, vx.P() - vxParent.P()) * M_180_PI; |
| } |
| |
| } |
| |
| |
| |
| |
| |
| SkVD::Keyframe SkVD::getKeyframe(double frame) const |
| { |
| Keyframe kf; |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| kf.m_keyframes[p] = m_params[p]->getKeyframeAt(frame); |
| |
| return kf; |
| } |
| |
| |
| |
| void SkVD::setKeyframe(double frame) |
| { |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| m_params[p]->setKeyframe(m_params[p]->getKeyframeAt(frame)); |
| } |
| |
| |
| |
| bool SkVD::setKeyframe(const SkVD::Keyframe &values) |
| { |
| bool keyWasSet = false; |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| if (values.m_keyframes[p].m_isKeyframe) { |
| m_params[p]->setKeyframe(values.m_keyframes[p]); |
| keyWasSet = true; |
| } |
| |
| return keyWasSet; |
| } |
| |
| |
| |
| bool SkVD::setKeyframe( |
| const SkVD::Keyframe &values, double frame, double easeIn, double easeOut) |
| { |
| bool keyWasSet = false; |
| |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| if (values.m_keyframes[p].m_isKeyframe) { |
| TDoubleKeyframe kf(values.m_keyframes[p]); |
| kf.m_frame = frame; |
| |
| if (easeIn >= 0.0) |
| kf.m_speedIn = TPointD(-easeIn, kf.m_speedIn.y); |
| if (easeOut >= 0.0) |
| kf.m_speedOut = TPointD(easeOut, kf.m_speedOut.y); |
| |
| m_params[p]->setKeyframe(kf); |
| keyWasSet = true; |
| } |
| |
| return keyWasSet; |
| } |
| |
| |
| |
| bool SkVD::isKeyframe(double frame) const |
| { |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| if (m_params[p]->isKeyframe(frame)) |
| return true; |
| |
| return false; |
| } |
| |
| |
| |
| bool SkVD::isFullKeyframe(double frame) const |
| { |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| if (!m_params[p]->isKeyframe(frame)) |
| return false; |
| |
| return true; |
| } |
| |
| |
| |
| void SkVD::deleteKeyframe(double frame) |
| { |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| m_params[p]->deleteKeyframe(frame); |
| } |
| |
| |
| |
| void SkVD::saveData(TOStream &os) |
| { |
| for (int p = 0; p < PARAMS_COUNT; ++p) |
| if (!m_params[p]->isDefault()) |
| os.child(::parNames[p]) << *m_params[p]; |
| } |
| |
| |
| |
| void SkVD::loadData(TIStream &is) |
| { |
| std::string tagName; |
| |
| while (is.matchTag(tagName)) { |
| int p; |
| for (p = 0; p < PARAMS_COUNT; ++p) { |
| if (tagName == parNames[p]) { |
| is >> *m_params[p], is.matchEndTag(); |
| break; |
| } |
| } |
| |
| if (p >= PARAMS_COUNT) |
| is.skipCurrentTag(); |
| } |
| } |
| |
| |
| |
| |
| |
| class PlasticSkeletonDeformation::Imp : public TParamObserver |
| { |
| public: |
| PlasticSkeletonDeformation *m_back; |
| |
| SkeletonSet m_skeletons; |
| SkVDSet m_vds; |
| |
| TDoubleParamP m_skelIdsParam; |
| |
| std::set<TParamObserver *> m_observers; |
| |
| TSyntax::Grammar *m_grammar; |
| |
| |
| |
| |
| |
| public: |
| Imp(PlasticSkeletonDeformation *back); |
| ~Imp(); |
| |
| Imp(PlasticSkeletonDeformation *back, const Imp &other); |
| Imp &operator=(const Imp &other); |
| |
| PlasticSkeleton &skeleton(int skelId) const; |
| SkVD &vertexDeformation(const QString &name) const; |
| |
| void attach(int skeletonId, PlasticSkeleton *skeleton); |
| void detach(int skeletonId); |
| |
| void attachVertex(const QString &name, int skelId, int v); |
| void detachVertex(const QString &name, int skelId, int v); |
| void rebindVertex(const QString &name, int skelId, const QString &newName); |
| |
| void touchParams(SkVD &vd); |
| |
| |
| void updateBranchPositions( |
| const PlasticSkeleton &originalSkeleton, PlasticSkeleton &deformedSkeleton, |
| double frame, int v); |
| |
| void onChange(const TParamChange &change); |
| |
| private: |
| |
| Imp(const Imp &other); |
| }; |
| |
| |
| |
| PlasticSkeletonDeformation::Imp::Imp(PlasticSkeletonDeformation *back) |
| : m_back(back), m_skelIdsParam(1.0), m_grammar() |
| { |
| m_skelIdsParam->setName("Skeleton Id"); |
| m_skelIdsParam->addObserver(this); |
| } |
| |
| |
| |
| PlasticSkeletonDeformation::Imp::~Imp() |
| { |
| m_skelIdsParam->removeObserver(this); |
| |
| SkVDSet::iterator dt, dEnd(m_vds.end()); |
| for (dt = m_vds.begin(); dt != dEnd; ++dt) |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) |
| dt->m_vd.m_params[p]->removeObserver(this); |
| } |
| |
| |
| |
| PlasticSkeletonDeformation::Imp::Imp(PlasticSkeletonDeformation *back, const Imp &other) |
| : m_back(back), m_skelIdsParam(other.m_skelIdsParam->clone()), m_grammar() |
| { |
| m_skelIdsParam->setGrammar(m_grammar); |
| m_skelIdsParam->addObserver(this); |
| |
| |
| SkeletonSet::const_iterator st, sEnd(other.m_skeletons.end()); |
| for (st = other.m_skeletons.begin(); st != sEnd; ++st) |
| m_skeletons.insert(SkeletonSet::value_type( |
| st->get_left(), new PlasticSkeleton(*st->get_right()))); |
| |
| |
| SkVD vd; |
| |
| SkVDSet::const_iterator dt, dEnd(other.m_vds.end()); |
| for (dt = other.m_vds.begin(); dt != dEnd; ++dt) { |
| VDKey vdKey = {dt->m_name, dt->m_hookNumber, dt->m_vIndices}; |
| |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) { |
| TDoubleParamP ¶m = vdKey.m_vd.m_params[p]; |
| |
| param = TDoubleParamP(dt->m_vd.m_params[p]->clone()); |
| |
| param->setGrammar(m_grammar); |
| param->addObserver(this); |
| } |
| |
| m_vds.insert(vdKey); |
| } |
| } |
| |
| |
| |
| PlasticSkeletonDeformation::Imp &PlasticSkeletonDeformation::Imp::operator=(const Imp &other) |
| { |
| *m_skelIdsParam = *other.m_skelIdsParam; |
| m_skelIdsParam->setGrammar(m_grammar); |
| |
| |
| |
| |
| SkVDSet::iterator dt, dEnd(m_vds.end()); |
| SkVDSet::const_iterator st, sEnd(other.m_vds.end()); |
| |
| for (dt = m_vds.begin(); dt != dEnd; ++dt) { |
| |
| st = other.m_vds.find(dt->m_name); |
| if (st != sEnd) |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) { |
| TDoubleParam ¶m = *dt->m_vd.m_params[p]; |
| |
| param = *st->m_vd.m_params[p]; |
| param.setGrammar(m_grammar); |
| } |
| } |
| |
| return *this; |
| } |
| |
| |
| |
| PlasticSkeleton &PlasticSkeletonDeformation::Imp::skeleton(int skelId) const |
| { |
| SkeletonSet::left_map::const_iterator st(m_skeletons.left.find(skelId)); |
| assert(st != m_skeletons.left.end()); |
| |
| return *st->second; |
| } |
| |
| |
| |
| SkVD &PlasticSkeletonDeformation::Imp::vertexDeformation(const QString &name) const |
| { |
| SkVDSet::const_iterator vdt(m_vds.find(name)); |
| assert(vdt != m_vds.end()); |
| |
| return vdt->m_vd; |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::attach(int skeletonId, PlasticSkeleton *skeleton) |
| { |
| assert(skeleton); |
| |
| |
| assert(m_skeletons.left.find(skeletonId) == m_skeletons.left.end()); |
| |
| m_skeletons.insert(SkeletonSet::value_type(skeletonId, skeleton)); |
| |
| |
| tcg::list<PlasticSkeleton::vertex_type> &vertices = skeleton->vertices(); |
| if (!vertices.empty()) { |
| tcg::list<PlasticSkeletonVertex>::iterator vt, vEnd(vertices.end()); |
| for (vt = vertices.begin(); vt != vEnd; ++vt) |
| attachVertex(vt->name(), skeletonId, vt.index()); |
| } |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::detach(int skeletonId) |
| { |
| |
| tcg::list<PlasticSkeleton::vertex_type> &vertices = skeleton(skeletonId).vertices(); |
| if (!vertices.empty()) { |
| tcg::list<PlasticSkeletonVertex>::iterator vt, vEnd(vertices.end()); |
| for (vt = vertices.begin(); vt != vEnd; ++vt) |
| detachVertex(vt->name(), skeletonId, vt.index()); |
| } |
| |
| |
| m_skeletons.left.erase(skeletonId); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::attachVertex(const QString &name, int skelId, int v) |
| { |
| struct locals { |
| |
| static int newHookNumber(Imp *imp) |
| { |
| int h = 1; |
| |
| SkVDByHookNumber::iterator vdt, vdEnd(imp->m_vds.get<int>().end()); |
| for (vdt = imp->m_vds.get<int>().begin(); vdt != vdEnd && vdt->m_hookNumber == h; ++vdt, ++h) |
| ; |
| |
| return h; |
| } |
| |
| }; |
| |
| |
| SkVDSet::iterator vdt(m_vds.find(name)); |
| if (vdt == m_vds.end()) { |
| VDKey vdKey = {name, locals::newHookNumber(this)}; |
| touchParams(vdKey.m_vd); |
| |
| vdt = m_vds.insert(vdKey).first; |
| } |
| |
| |
| vdt->m_vIndices.insert(std::make_pair(skelId, v)); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::detachVertex(const QString &name, int skelId, int v) |
| { |
| SkVDSet::iterator vdt = m_vds.find(name); |
| assert(vdt != m_vds.end()); |
| |
| |
| int count = vdt->m_vIndices.erase(skelId); |
| assert(count > 0); |
| |
| if (vdt->m_vIndices.empty()) { |
| |
| SkVD &vd = vdt->m_vd; |
| |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) |
| vd.m_params[p]->removeObserver(this); |
| |
| m_vds.erase(vdt); |
| } |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::rebindVertex( |
| const QString &name, int skelId, const QString &newName) |
| { |
| if (name == newName) |
| return; |
| |
| SkVDSet::iterator oldVdt = m_vds.find(name); |
| if (oldVdt == m_vds.end()) |
| return; |
| |
| std::map<int, int>::iterator vit = oldVdt->m_vIndices.find(skelId); |
| assert(vit != oldVdt->m_vIndices.end()); |
| |
| int v = vit->second; |
| |
| SkVDSet::iterator newVdt = m_vds.find(newName); |
| if (newVdt != m_vds.end()) { |
| detachVertex(name, skelId, v); |
| attachVertex(newName, skelId, v); |
| } else { |
| |
| if (oldVdt->m_vIndices.size() == 1) { |
| |
| VDKey vdKey(*oldVdt); |
| vdKey.m_name = newName; |
| |
| m_vds.erase(name); |
| m_vds.insert(vdKey); |
| } else { |
| |
| detachVertex(name, skelId, v); |
| attachVertex(newName, skelId, v); |
| |
| newVdt = m_vds.find(newName); |
| |
| |
| SkVD &oldVd = oldVdt->m_vd, &newVd = newVdt->m_vd; |
| |
| int p, pCount = SkVD::PARAMS_COUNT; |
| for (p = 0; p != pCount; ++p) |
| *newVd.m_params[p] = *oldVd.m_params[p]; |
| } |
| } |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::touchParams(SkVD &vd) |
| { |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) { |
| if (vd.m_params[p]) |
| continue; |
| |
| TDoubleParam *param = new TDoubleParam; |
| param->setName(parNames[p]); |
| param->setMeasureName(parMeasures[p]); |
| param->setGrammar(m_grammar); |
| |
| vd.m_params[p] = param; |
| |
| param->addObserver(this); |
| } |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::onChange(const TParamChange &change) |
| { |
| |
| |
| PlasticDeformerStorage::instance()->invalidateDeformation( |
| m_back, PlasticDeformerStorage::NONE); |
| |
| |
| std::set<TParamObserver *>::iterator ot, oEnd(m_observers.end()); |
| for (ot = m_observers.begin(); ot != oEnd; ++ot) |
| (*ot)->onChange(change); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::Imp::updateBranchPositions( |
| const PlasticSkeleton &originalSkeleton, PlasticSkeleton &deformedSkeleton, |
| double frame, int v) |
| { |
| struct locals { |
| |
| static void buildParentDirection(const PlasticSkeleton &skel, int v, TPointD &dir) |
| { |
| assert(v >= 0); |
| |
| const PlasticSkeletonVertex &vx = skel.vertex(v); |
| |
| int vParent = vx.parent(); |
| if (vParent < 0) |
| return; |
| |
| const TPointD &dir_ = tcg::point_ops::direction( |
| skel.vertex(vParent).P(), vx.P(), 1e-4); |
| |
| if (dir_ != tcg::point_ops::NaP<TPointD>()) |
| dir = dir_; |
| else |
| buildParentDirection(skel, vParent, dir); |
| } |
| }; |
| |
| PlasticSkeletonVertex &dvx = deformedSkeleton.vertex(v); |
| int vParent = dvx.parent(); |
| if (vParent >= 0) { |
| |
| const TPointD &ovxPos = originalSkeleton.vertex(v).P(); |
| const TPointD &ovxParentPos = originalSkeleton.vertex(vParent).P(); |
| |
| |
| TPointD oDir(1.0, 0.0), dDir(1.0, 0.0); |
| |
| locals::buildParentDirection(originalSkeleton, vParent, oDir); |
| locals::buildParentDirection(deformedSkeleton, vParent, dDir); |
| |
| |
| const SkVD &vd = m_vds.find(dvx.name())->m_vd; |
| |
| double a = tcg::point_ops::angle(oDir, ovxPos - ovxParentPos) * M_180_PI; |
| double d = tcg::point_ops::dist(ovxParentPos, ovxPos); |
| |
| double aDelta = vd.m_params[SkVD::ANGLE]->getValue(frame); |
| double dDelta = vd.m_params[SkVD::DISTANCE]->getValue(frame); |
| |
| dvx.P() = deformedSkeleton.vertex(vParent).P() + |
| (d + dDelta) * (TRotation(a + aDelta) * dDir); |
| } |
| |
| |
| PlasticSkeleton::vertex_type::edges_iterator et, eEnd(dvx.edgesEnd()); |
| for (et = dvx.edgesBegin(); et != eEnd; ++et) { |
| int vChild = deformedSkeleton.edge(*et).vertex(1); |
| if (vChild == v) |
| continue; |
| |
| updateBranchPositions(originalSkeleton, deformedSkeleton, frame, vChild); |
| } |
| } |
| |
| |
| |
| |
| |
| PlasticSkeletonDeformation::PlasticSkeletonDeformation() |
| : m_imp(new Imp(this)) |
| { |
| } |
| |
| |
| |
| PlasticSkeletonDeformation::PlasticSkeletonDeformation(const PlasticSkeletonDeformation &other) |
| : TSmartObject(m_classCode), m_imp(new Imp(this, *other.m_imp)) |
| { |
| |
| SkeletonSet::iterator st, sEnd(m_imp->m_skeletons.end()); |
| for (st = m_imp->m_skeletons.begin(); st != sEnd; ++st) |
| st->get_right()->addListener(this); |
| } |
| |
| |
| |
| PlasticSkeletonDeformation::~PlasticSkeletonDeformation() |
| { |
| |
| SkeletonSet::iterator st, sEnd(m_imp->m_skeletons.end()); |
| for (st = m_imp->m_skeletons.begin(); st != sEnd; ++st) |
| st->get_right()->removeListener(this); |
| } |
| |
| |
| |
| PlasticSkeletonDeformation &PlasticSkeletonDeformation::operator=(const PlasticSkeletonDeformation &other) |
| { |
| |
| |
| |
| *m_imp = *other.m_imp; |
| return *this; |
| } |
| |
| |
| |
| bool PlasticSkeletonDeformation::empty() const |
| { |
| return m_imp->m_skeletons.empty(); |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::skeletonsCount() const |
| { |
| return m_imp->m_skeletons.size(); |
| } |
| |
| |
| |
| namespace |
| { |
| namespace skeletonIds |
| { |
| typedef boost::bimap<int, PlasticSkeletonP>::left_map::const_iterator iter_type; |
| typedef iter_type::value_type value_type; |
| |
| inline int func_(const value_type &val) { return val.first; } |
| } |
| } |
| |
| void PlasticSkeletonDeformation::skeletonIds(skelId_iterator &begin, skelId_iterator &end) const |
| { |
| using namespace ::skeletonIds; |
| |
| typedef tcg::function<int (*)(const value_type &), func_> func; |
| typedef boost::transform_iterator<func, iter_type> adapt_it; |
| |
| begin = adapt_it(m_imp->m_skeletons.left.begin()); |
| end = adapt_it(m_imp->m_skeletons.left.end()); |
| } |
| |
| |
| |
| TDoubleParamP PlasticSkeletonDeformation::skeletonIdsParam() const |
| { |
| return m_imp->m_skelIdsParam; |
| } |
| |
| |
| |
| PlasticSkeletonP PlasticSkeletonDeformation::skeleton(double frame) const |
| { |
| return skeleton(skeletonId(frame)); |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::skeletonId(double frame) const |
| { |
| return m_imp->m_skelIdsParam->getValue(frame); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::attach(int skeletonId, PlasticSkeleton *skeleton) |
| { |
| m_imp->attach(skeletonId, skeleton); |
| |
| skeleton->addListener(this); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::detach(int skeletonId) |
| { |
| SkeletonSet::left_map::iterator st(m_imp->m_skeletons.left.find(skeletonId)); |
| if (st != m_imp->m_skeletons.left.end()) { |
| st->second->removeListener(this); |
| m_imp->detach(skeletonId); |
| } |
| } |
| |
| |
| |
| PlasticSkeletonP PlasticSkeletonDeformation::skeleton(int skeletonId) const |
| { |
| SkeletonSet::left_map::const_iterator st = m_imp->m_skeletons.left.find(skeletonId); |
| return (st == m_imp->m_skeletons.left.end()) ? PlasticSkeletonP() : st->second; |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::skeletonId(PlasticSkeleton *skeleton) const |
| { |
| SkeletonSet::right_map::const_iterator st = m_imp->m_skeletons.right.find(skeleton); |
| return (st == m_imp->m_skeletons.right.end()) ? -(std::numeric_limits<int>::max)() : st->second; |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::vertexDeformationsCount() const |
| { |
| return m_imp->m_vds.size(); |
| } |
| |
| |
| |
| SkVD *PlasticSkeletonDeformation::vertexDeformation(const QString &vxName) const |
| { |
| SkVDSet::const_iterator vdt = m_imp->m_vds.find(vxName); |
| return (vdt == m_imp->m_vds.end()) ? (SkVD *)0 : &vdt->m_vd; |
| } |
| |
| |
| |
| SkVD *PlasticSkeletonDeformation::vertexDeformation(int skelId, int v) const |
| { |
| const QString &name = skeleton(skelId)->vertex(v).name(); |
| return vertexDeformation(name); |
| } |
| |
| |
| |
| namespace |
| { |
| namespace vertexDeformations |
| { |
| inline std::pair<const QString *, SkVD *> func_(const VDKey &vdKey) |
| { |
| return std::make_pair(&vdKey.m_name, &vdKey.m_vd); |
| } |
| } |
| } |
| |
| void PlasticSkeletonDeformation::vertexDeformations(vd_iterator &begin, vd_iterator &end) const |
| { |
| using namespace ::vertexDeformations; |
| |
| typedef std::pair<const QString *, SkVD *> (*func_type)(const VDKey &vdKey); |
| typedef tcg::function<func_type, func_> func; |
| typedef boost::transform_iterator<func, SkVDSet::const_iterator> adapt_it; |
| |
| begin = adapt_it(m_imp->m_vds.begin()); |
| end = adapt_it(m_imp->m_vds.end()); |
| } |
| |
| |
| |
| namespace |
| { |
| namespace vdSkeletonVertices |
| { |
| inline std::pair<int, int> func_(const std::map<int, int>::value_type &val) |
| { |
| return std::make_pair(val.first, val.second); |
| } |
| } |
| } |
| |
| void PlasticSkeletonDeformation::vdSkeletonVertices(const QString &vertexName, |
| vx_iterator &begin, vx_iterator &end) const |
| { |
| using namespace ::vdSkeletonVertices; |
| |
| typedef std::pair<int, int> (*func_type)(const std::map<int, int>::value_type &); |
| typedef tcg::function<func_type, func_> func; |
| typedef boost::transform_iterator<func, std::map<int, int>::const_iterator> adapt_it; |
| |
| SkVDSet::const_iterator nt(m_imp->m_vds.find(vertexName)); |
| |
| if (nt == m_imp->m_vds.end()) |
| begin = adapt_it(), end = adapt_it(); |
| else |
| begin = adapt_it(nt->m_vIndices.begin()), end = adapt_it(nt->m_vIndices.end()); |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::hookNumber(const QString &name) const |
| { |
| SkVDSet::const_iterator nt(m_imp->m_vds.find(name)); |
| return (nt == m_imp->m_vds.end()) ? -1 : nt->m_hookNumber; |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::hookNumber(int skelId, int v) const |
| { |
| const QString &name = skeleton(skelId)->vertex(v).name(); |
| return hookNumber(name); |
| } |
| |
| |
| |
| QString PlasticSkeletonDeformation::vertexName(int hookNumber) const |
| { |
| const SkVDByHookNumber &vds = m_imp->m_vds.get<int>(); |
| |
| SkVDByHookNumber::const_iterator ht(vds.find(hookNumber)); |
| return (ht == vds.end()) ? QString() : ht->m_name; |
| } |
| |
| |
| |
| int PlasticSkeletonDeformation::vertexIndex(int hookNumber, int skelId) const |
| { |
| const SkVDByHookNumber &vds = m_imp->m_vds.get<int>(); |
| |
| SkVDByHookNumber::const_iterator ht(vds.find(hookNumber)); |
| if (ht == vds.end()) |
| return -1; |
| |
| std::map<int, int>::const_iterator st(ht->m_vIndices.find(skelId)); |
| return (st == ht->m_vIndices.end()) ? -1 : st->second; |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::getKeyframeAt(double frame, SkDKey &keyframe) const |
| { |
| keyframe.m_skelIdKeyframe = m_imp->m_skelIdsParam->getKeyframeAt(frame); |
| keyframe.m_vertexKeyframes.clear(); |
| |
| SkVDSet::const_iterator dt, dEnd(m_imp->m_vds.end()); |
| for (dt = m_imp->m_vds.begin(); dt != dEnd; ++dt) |
| keyframe.m_vertexKeyframes.insert(std::make_pair(dt->m_name, dt->m_vd.getKeyframe(frame))); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::setKeyframe(double frame) |
| { |
| m_imp->m_skelIdsParam->setKeyframe(frame); |
| |
| SkVDSet::iterator dt, dEnd(m_imp->m_vds.end()); |
| for (dt = m_imp->m_vds.begin(); dt != dEnd; ++dt) |
| dt->m_vd.setKeyframe(frame); |
| } |
| |
| |
| |
| bool PlasticSkeletonDeformation::setKeyframe(const SkDKey &keyframe) |
| { |
| bool keyWasSet = false; |
| |
| if (keyframe.m_skelIdKeyframe.m_isKeyframe) { |
| m_imp->m_skelIdsParam->setKeyframe(keyframe.m_skelIdKeyframe); |
| keyWasSet = true; |
| } |
| |
| const std::map<QString, SkVD::Keyframe> &vdKeys = keyframe.m_vertexKeyframes; |
| |
| |
| std::map<QString, SkVD::Keyframe>::const_iterator kt, kEnd(vdKeys.end()); |
| for (kt = vdKeys.begin(); kt != vdKeys.end(); ++kt) { |
| |
| SkVDSet::iterator vdt = m_imp->m_vds.find(kt->first); |
| if (vdt != m_imp->m_vds.end()) { |
| |
| keyWasSet = vdt->m_vd.setKeyframe(kt->second) || keyWasSet; |
| } |
| } |
| |
| return keyWasSet; |
| } |
| |
| |
| |
| bool PlasticSkeletonDeformation::setKeyframe( |
| const SkDKey &keyframe, double frame, double easeIn, double easeOut) |
| { |
| bool keyWasSet = false; |
| |
| if (keyframe.m_skelIdKeyframe.m_isKeyframe) { |
| TDoubleKeyframe kf(keyframe.m_skelIdKeyframe); |
| kf.m_frame = frame; |
| |
| m_imp->m_skelIdsParam->setKeyframe(kf); |
| keyWasSet = true; |
| } |
| |
| const std::map<QString, SkVD::Keyframe> &vdKeys = keyframe.m_vertexKeyframes; |
| |
| |
| std::map<QString, SkVD::Keyframe>::const_iterator kt, kEnd(vdKeys.end()); |
| for (kt = vdKeys.begin(); kt != vdKeys.end(); ++kt) { |
| |
| SkVDSet::iterator vdt = m_imp->m_vds.find(kt->first); |
| if (vdt != m_imp->m_vds.end()) { |
| |
| keyWasSet = vdt->m_vd.setKeyframe(kt->second, frame, easeIn, easeOut) || keyWasSet; |
| } |
| } |
| |
| return keyWasSet; |
| } |
| |
| |
| |
| bool PlasticSkeletonDeformation::isKeyframe(double frame) const |
| { |
| if (m_imp->m_skelIdsParam->isKeyframe(frame)) |
| return true; |
| |
| SkVDSet::const_iterator dt, dEnd(m_imp->m_vds.end()); |
| for (dt = m_imp->m_vds.begin(); dt != dEnd; ++dt) |
| if (dt->m_vd.isKeyframe(frame)) |
| return true; |
| |
| return false; |
| } |
| |
| |
| |
| bool PlasticSkeletonDeformation::isFullKeyframe(double frame) const |
| { |
| if (!m_imp->m_skelIdsParam->isKeyframe(frame)) |
| return false; |
| |
| SkVDSet::const_iterator dt, dEnd(m_imp->m_vds.end()); |
| for (dt = m_imp->m_vds.begin(); dt != dEnd; ++dt) |
| if (!dt->m_vd.isFullKeyframe(frame)) |
| return false; |
| |
| return true; |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::deleteKeyframe(double frame) |
| { |
| m_imp->m_skelIdsParam->deleteKeyframe(frame); |
| |
| SkVDSet::iterator dt, dEnd(m_imp->m_vds.end()); |
| for (dt = m_imp->m_vds.begin(); dt != dEnd; ++dt) |
| dt->m_vd.deleteKeyframe(frame); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::storeDeformedSkeleton(int skelId, double frame, PlasticSkeleton &skeleton) const |
| { |
| |
| const PlasticSkeletonP &origSkel = this->skeleton(skelId); |
| skeleton = origSkel ? *origSkel : PlasticSkeleton(); |
| |
| |
| if (!skeleton.vertices().empty()) |
| m_imp->updateBranchPositions(*origSkel, skeleton, frame, skeleton.vertices().begin().m_idx); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::updatePosition( |
| const PlasticSkeleton &originalSkeleton, PlasticSkeleton &deformedSkeleton, |
| double frame, int v, const TPointD &pos) |
| { |
| const PlasticSkeletonVertex &vx = deformedSkeleton.vertex(v); |
| int vParent = vx.parent(); |
| |
| const TPointD &vParentPos = deformedSkeleton.vertex(vParent).P(); |
| const TPointD &vPos = deformedSkeleton.vertex(v).P(); |
| |
| SkVD &vd = m_imp->m_vds.find(vx.name())->m_vd; |
| |
| |
| |
| |
| double aDelta = tcg::point_ops::angle(vPos - vParentPos, pos - vParentPos) * M_180_PI, |
| dDelta = tcg::point_ops::dist(vParentPos, pos) - tcg::point_ops::dist(vParentPos, vPos), |
| |
| a = tcrop(vd.m_params[SkVD::ANGLE]->getValue(frame) + aDelta, vx.m_minAngle, vx.m_maxAngle), |
| d = vd.m_params[SkVD::DISTANCE]->getValue(frame) + dDelta; |
| |
| vd.m_params[SkVD::ANGLE]->setValue(frame, a); |
| vd.m_params[SkVD::DISTANCE]->setValue(frame, d); |
| |
| m_imp->updateBranchPositions(originalSkeleton, deformedSkeleton, frame, v); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::updateAngle( |
| const PlasticSkeleton &originalSkeleton, PlasticSkeleton &deformedSkeleton, |
| double frame, int v, const TPointD &pos) |
| { |
| const PlasticSkeletonVertex &vx = deformedSkeleton.vertex(v); |
| int vParent = vx.parent(); |
| |
| const TPointD &vParentPos = deformedSkeleton.vertex(vParent).P(); |
| |
| |
| |
| SkVD &vd = m_imp->m_vds.find(vx.name())->m_vd; |
| |
| double aDelta = tcg::point_ops::angle(vx.P() - vParentPos, pos - vParentPos) * M_180_PI, |
| a = tcrop(vd.m_params[SkVD::ANGLE]->getValue(frame) + aDelta, vx.m_minAngle, vx.m_maxAngle); |
| |
| vd.m_params[SkVD::ANGLE]->setValue(frame, a); |
| |
| m_imp->updateBranchPositions(originalSkeleton, deformedSkeleton, frame, v); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::addVertex(PlasticSkeleton *skel, int v) |
| { |
| int skelId = skeletonId(skel); |
| assert(skelId >= 0); |
| |
| m_imp->attachVertex(skel->vertex(v).name(), skelId, v); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::insertVertex(PlasticSkeleton *skel, int v) |
| { |
| int skelId = skeletonId(skel); |
| assert(skelId >= 0); |
| |
| m_imp->attachVertex(skel->vertex(v).name(), skelId, v); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::deleteVertex(PlasticSkeleton *skel, int v) |
| { |
| assert(v > 0); |
| |
| int skelId = skeletonId(skel); |
| assert(skelId >= 0); |
| |
| |
| m_imp->detachVertex(skel->vertex(v).name(), skelId, v); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::vertexNameChange( |
| PlasticSkeleton *skel, int v, const QString &newName) |
| { |
| int skelId = skeletonId(skel); |
| assert(skelId >= 0); |
| |
| m_imp->rebindVertex(skel->vertex(v).name(), skelId, newName); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::clear(PlasticSkeleton *skel) |
| { |
| int skelId = skeletonId(skel); |
| assert(skelId >= 0); |
| |
| m_imp->detach(skelId); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::addObserver(TParamObserver *observer) |
| { |
| m_imp->m_observers.insert(observer); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::removeObserver(TParamObserver *observer) |
| { |
| m_imp->m_observers.erase(observer); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::setGrammar(TSyntax::Grammar *grammar) |
| { |
| SkVDSet::iterator vdt, vdEnd(m_imp->m_vds.end()); |
| for (vdt = m_imp->m_vds.begin(); vdt != vdEnd; ++vdt) { |
| SkVD &vd = vdt->m_vd; |
| |
| for (int c = 0; c != SkVD::PARAMS_COUNT; ++c) |
| vd.m_params[c]->setGrammar(grammar); |
| } |
| |
| m_imp->m_skelIdsParam->setGrammar(grammar); |
| |
| m_imp->m_grammar = grammar; |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::saveData(TOStream &os) |
| { |
| |
| os.openChild("VertexDeforms"); |
| { |
| SkVDSet::iterator vdt, vdEnd(m_imp->m_vds.end()); |
| for (vdt = m_imp->m_vds.begin(); vdt != vdEnd; ++vdt) |
| { |
| os.child("Name") << vdt->m_name; |
| os.child("Hook") << vdt->m_hookNumber; |
| os.child("VD") << vdt->m_vd; |
| } |
| } |
| os.closeChild(); |
| |
| |
| os.child("SkelIdsParam") << *m_imp->m_skelIdsParam; |
| |
| |
| os.openChild("Skeletons"); |
| { |
| SkeletonSet::iterator st, sEnd(m_imp->m_skeletons.end()); |
| for (st = m_imp->m_skeletons.begin(); st != sEnd; ++st) { |
| os.child("SkelId") << st->get_left(); |
| os.child("Skeleton") << *st->get_right(); |
| } |
| } |
| os.closeChild(); |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::loadData(TIStream &is) |
| { |
| if (is.getVersion() < VersionNumber(1, 21)) { |
| loadData_prerelease(is); |
| return; |
| } |
| |
| int skeletonId; |
| PlasticSkeleton *skeleton; |
| |
| std::string tagName; |
| while (is.openChild(tagName)) { |
| if (tagName == "VertexDeforms") { |
| VDKey vKey; |
| |
| while (is.openChild(tagName)) { |
| if (tagName == "Name") |
| is >> vKey.m_name, is.matchEndTag(); |
| else if (tagName == "Hook") |
| is >> vKey.m_hookNumber, is.matchEndTag(); |
| else if (tagName == "VD") { |
| m_imp->touchParams(vKey.m_vd); |
| is >> vKey.m_vd, is.matchEndTag(); |
| |
| m_imp->m_vds.insert(vKey); |
| |
| vKey = VDKey(); |
| } else |
| is.skipCurrentTag(); |
| } |
| |
| is.matchEndTag(); |
| } else if (tagName == "SkelIdsParam") |
| is >> *m_imp->m_skelIdsParam, is.matchEndTag(); |
| else if (tagName == "Skeletons") { |
| while (is.openChild(tagName)) { |
| if (tagName == "SkelId") |
| is >> skeletonId, is.matchEndTag(); |
| else if (tagName == "Skeleton") { |
| skeleton = new PlasticSkeleton; |
| is >> *skeleton, is.matchEndTag(); |
| |
| attach(skeletonId, skeleton); |
| skeletonId = 0, skeleton = 0; |
| } else |
| is.skipCurrentTag(); |
| } |
| |
| is.matchEndTag(); |
| } else |
| is.skipCurrentTag(); |
| } |
| } |
| |
| |
| |
| void PlasticSkeletonDeformation::loadData_prerelease(TIStream &is) |
| { |
| struct locals { |
| |
| static void buildParentDirection(const PlasticSkeleton &skel, int v, TPointD &dir) |
| { |
| assert(v >= 0); |
| |
| const PlasticSkeletonVertex &vx = skel.vertex(v); |
| |
| int vParent = vx.parent(); |
| if (vParent < 0) |
| return; |
| |
| const TPointD &dir_ = tcg::point_ops::direction( |
| skel.vertex(vParent).P(), vx.P(), 1e-4); |
| |
| if (dir_ != tcg::point_ops::NaP<TPointD>()) |
| dir = dir_; |
| else |
| buildParentDirection(skel, vParent, dir); |
| } |
| |
| |
| |
| static void adjust(SkD &sd, int v) |
| { |
| |
| PlasticSkeleton &skeleton = *sd.skeleton(1); |
| |
| PlasticSkeletonVertex &vx = skeleton.vertex(v); |
| int vParent = vx.parent(); |
| if (vParent >= 0) { |
| |
| const TPointD &vxPos = skeleton.vertex(v).P(); |
| const TPointD &vxParentPos = skeleton.vertex(vParent).P(); |
| |
| |
| TPointD dir(1.0, 0.0); |
| |
| buildParentDirection(skeleton, vParent, dir); |
| |
| |
| SkVD &vd = sd.m_imp->m_vds.find(vx.name())->m_vd; |
| |
| double a = tcg::point_ops::angle(dir, vxPos - vxParentPos) * M_180_PI; |
| double d = tcg::point_ops::dist(vxParentPos, vxPos); |
| |
| { |
| TDoubleParamP param(vd.m_params[SkVD::ANGLE]); |
| param->setDefaultValue(0.0); |
| |
| int k, kCount = param->getKeyframeCount(); |
| for (k = 0; k != kCount; ++k) { |
| TDoubleKeyframe kf(param->getKeyframe(k)); |
| kf.m_value -= a; |
| param->setKeyframe(k, kf); |
| } |
| } |
| |
| { |
| TDoubleParamP param(vd.m_params[SkVD::DISTANCE]); |
| param->setDefaultValue(0.0); |
| |
| int k, kCount = param->getKeyframeCount(); |
| for (k = 0; k != kCount; ++k) { |
| TDoubleKeyframe kf(param->getKeyframe(k)); |
| kf.m_value -= d; |
| param->setKeyframe(k, kf); |
| } |
| } |
| } |
| |
| |
| PlasticSkeleton::vertex_type::edges_iterator et, eEnd(vx.edgesEnd()); |
| for (et = vx.edgesBegin(); et != eEnd; ++et) { |
| int vChild = skeleton.edge(*et).vertex(1); |
| if (vChild == v) |
| continue; |
| |
| adjust(sd, vChild); |
| } |
| } |
| }; |
| |
| PlasticSkeletonP skeleton(new PlasticSkeleton); |
| |
| std::string tagName; |
| while (is.openChild(tagName)) { |
| if (tagName == "Skeleton") |
| is >> *skeleton, is.matchEndTag(); |
| else if (tagName == "VertexDeforms") { |
| while (is.openChild(tagName)) { |
| if (tagName == "VD") { |
| VDKey vKey; |
| m_imp->touchParams(vKey.m_vd); |
| |
| is >> vKey.m_name, is >> vKey.m_vd; |
| is.closeChild(); |
| |
| |
| int v, vCount = skeleton->verticesCount(); |
| for (v = 0; v != vCount; ++v) |
| if (skeleton->vertex(v).name() == vKey.m_name) |
| break; |
| |
| assert(v < vCount); |
| vKey.m_hookNumber = skeleton->vertex(v).number(); |
| |
| m_imp->m_vds.insert(vKey); |
| } else |
| is.skipCurrentTag(); |
| } |
| |
| is.matchEndTag(); |
| } else |
| is.skipCurrentTag(); |
| } |
| |
| attach(1, skeleton.getPointer()); |
| |
| |
| locals::adjust(*this, 0); |
| } |
| |