/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "Animation.h" //common #define STL_USING_FUNCTIONAL #include "OdaSTL.h" //tv #include "TvDatabase.h" #include "TvInsert.h" //nw #include "NwDatabase.h" #include "NwModelItem.h" #include "NwColor.h" //nw saved animation #include "SavedAnimation/NwSavedAnimElement.h" #include "SavedAnimation/NwSavedAnimSelectAnim.h" #include "SavedAnimation/NwSavedAnimSelectKeyFrame.h" #include "SavedAnimation/NwSavedAnimFolder.h" #include "SavedAnimation/NwSavedAnimClip.h" #include "SavedAnimation/NwSavedAnimKeyFrame.h" #include "SavedAnimation/NwSavedAnimScene.h" #include "SavedAnimation/NwSavedAnimSceneFolder.h" #include "SavedAnimation/NwSavedAnimCamera.h" OdTvNwSavedAnimationEnumerator::OdTvNwSavedAnimationEnumerator(const OdNwObjectId& nwSavedAnimationId, OdTvDatabasePtr pTvDb, OdTvModelId modelId, mapNwObjId2TvIdsType&& nwOIds2TvIdsMap) : m_nwSavedAnimationId(nwSavedAnimationId) , m_pTvDb(pTvDb) , m_modelId(modelId) , m_NwOIds2TvIdsMap(std::move(nwOIds2TvIdsMap)) , m_cameraCount(0) { } OdTvNwSavedAnimationEnumerator::~OdTvNwSavedAnimationEnumerator() { } bool OdTvNwSavedAnimationEnumerator::enumAnimGroup(const OdNwSavedAnimGroup * pAnimGrp) { if (m_cameraCount > 0) { return false; } m_cameraCount++; OdTvDevicesIteratorPtr pDevIt = m_pTvDb->getDevicesIterator(); OdTvGsDevicePtr pDevice = pDevIt->getDevice().openObject(OdTv::kForWrite); OdTvGsViewId originalViewId = pDevice->viewAt(0); OdTvGsViewPtr pOriginalView = originalViewId.openObject(OdTv::kForWrite); OdTvGsViewId newViewId = pDevice->createView(OD_T("SecondView")); OdTvGsViewPtr pView = newViewId.openObject(OdTv::kForWrite); pView->addModel(m_modelId); pDevice->addView(newViewId); pView->setView(pOriginalView->position(), pOriginalView->target(), pOriginalView->upVector(), pOriginalView->fieldWidth(), pOriginalView->fieldHeight()); double viewfocalLength = pOriginalView->focalLength(); pView->setBackground(pOriginalView->getBackground()); pView->setVisualStyle(pOriginalView->getVisualStyle()); pView->setDefaultLightingColor(pOriginalView->defaultLightingColor()); pView->setDefaultLightingIntensity(pOriginalView->defaultLightingIntensity()); pView->enableDefaultLighting(pOriginalView->defaultLightingEnabled(), pOriginalView->defaultLightingType()); pOriginalView->setViewport(OdTvPoint2d(0., 0.), OdTvPoint2d(0.5, 1.)); pView->setBorderVisibility(true); pOriginalView->setBorderVisibility(true); pView->setViewport(OdTvPoint2d(0.5, 0.), OdTvPoint2d(1., 1.)); OdTvModelPtr pModel = m_modelId.openObject(OdTv::kForWrite); OdNwObjectIdArray ObjIdList; if (!pAnimGrp || pAnimGrp->getChildren(ObjIdList) != eOk) { return false; } auto keyFrameComparFn = [](const OdNwSavedAnimKeyFramePtr& a, const OdNwSavedAnimKeyFramePtr&b) { return a->getTime() < b->getTime(); }; std::set setKeyFrame(keyFrameComparFn); for (auto & sceneChildId : ObjIdList) { OdNwSavedAnimKeyFramePtr pKeyFrame = OdNwSavedAnimKeyFrame::cast(sceneChildId.safeOpenObject()); setKeyFrame.insert(pKeyFrame); } OdNwSavedAnimKeyFramePtr firstKf = *setKeyFrame.begin(); OdNwSavedAnimKeyFramePtr lastKf = *setKeyFrame.rbegin(); double kps = 24; double lastKfTime = lastKf->getTime(); size_t kfCount = setKeyFrame.size(); int totalKfnum = ceil(lastKfTime*kps) + 1; if (firstKf->getCameraProjection() == NwViewType::ORTHOGRAPHIC) { viewfocalLength =1; } OdGeQuaternion camq = firstKf->getCameraRotation(); OdGeMatrix3d matr = camq.getMatrix(); OdTvEntityId cameraId = pModel->appendCamera(OD_T("AnimatedCamera")); OdTvCameraPtr pCamera = cameraId.openObjectAsCamera(OdTv::kForWrite); double focalLength = OdZero(firstKf->getFocalDistance()) ? viewfocalLength : firstKf->getFocalDistance(); OdTvPoint target = firstKf->getCameraPosition() - matr.getCsZAxis() * focalLength; OdTvVector up = matr.getCsYAxis(); OdTvPoint position = firstKf->getCameraPosition(); double verticalAngle = firstKf->getCameraHeightField(); double horizontAngle = firstKf->getCameraViewAspect()*verticalAngle; pCamera->setAdjustLensLength(true); pCamera->setupCamera(position, target, up); double fw = 0; double fh = 0; if (firstKf->getCameraProjection() == NwViewType::PERSPECTIVE) { fw = 2*tan(verticalAngle/2.0)*focalLength; double asp = firstKf->getCameraViewAspect(); fh = fw / asp; pCamera->setViewParameters(fw, fh, true); } else { fh = firstKf->getCameraHeightField(); double aspect = firstKf->getCameraViewAspect(); fw = fh * aspect; pCamera->setViewParameters(fw, fh, false); } pCamera->setDisplayGlyph(true); pCamera->setDisplayTarget(true); pCamera->setAutoAdjust(false); OdTvAnimationContainerId contId; OdTvAnimationContainerPtr pContainer; OdTvAnimationActionId positionActionId, targetActionId, fieldsActionId, upActionId; OdTvAnimationActionPtr pPositionAction, pTargetAction, pFieldsAction, pUpAction; contId = m_pTvDb->createAnimationContainer(pAnimGrp->getDisplayName()); pContainer = contId.openObject(OdTv::kForWrite); targetActionId = m_pTvDb->createAnimationAction(OD_T("TargetPositionMoveAction")); pTargetAction = targetActionId.openObject(OdTv::kForWrite); pTargetAction->setFPS(kps); pTargetAction->setNumFrames(totalKfnum); positionActionId = m_pTvDb->createAnimationAction(OD_T("CameraPositionMoveAction")); pPositionAction = positionActionId.openObject(OdTv::kForWrite); pPositionAction->setFPS(kps); pPositionAction->setNumFrames(totalKfnum); fieldsActionId = m_pTvDb->createAnimationAction(OD_T("CameraFieldScaleAction")); pFieldsAction = fieldsActionId.openObject(OdTv::kForWrite); pFieldsAction->setFPS(kps); pFieldsAction->setNumFrames(totalKfnum); upActionId = m_pTvDb->createAnimationAction(OD_T("CameraUpMoveAction")); pUpAction = upActionId.openObject(OdTv::kForWrite); pUpAction->setFPS(kps); pUpAction->setNumFrames(totalKfnum); double prevFocalDistance = focalLength; for (OdNwSavedAnimKeyFramePtr kf : setKeyFrame) { double kfTime = kf->getTime(); int kftl = ceil(kfTime * kps); OdGeQuaternion camq = kf->getCameraRotation(); OdGeMatrix3d matr = camq.getMatrix(); double curFocalDistance = kf->getFocalDistance(); if (OdEqual(curFocalDistance, 0)) { ODA_ASSERT(!OdEqual(prevFocalDistance, 0)); curFocalDistance = prevFocalDistance; } else { prevFocalDistance = curFocalDistance; } ODA_ASSERT(!OdEqual(curFocalDistance, 0)); OdTvPoint newTarget = kf->getCameraPosition() - matr.getCsZAxis() * curFocalDistance; pTargetAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationX, newTarget.x - target.x, OdTvAnimationAction::kLinear); pTargetAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationY, newTarget.y - target.y, OdTvAnimationAction::kLinear); pTargetAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationZ, newTarget.z - target.z, OdTvAnimationAction::kLinear); OdTvPoint newPosition = kf->getCameraPosition(); pPositionAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationX, newPosition.x - position.x, OdTvAnimationAction::kLinear); pPositionAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationY, newPosition.y - position.y, OdTvAnimationAction::kLinear); pPositionAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationZ, newPosition.z - position.z, OdTvAnimationAction::kLinear); double verticalAngle = kf->getCameraHeightField(); double horizontAngle = kf->getCameraViewAspect()*verticalAngle; double kf_fw = 0; double kf_fh = 0; if (firstKf->getCameraProjection() == NwViewType::PERSPECTIVE) { kf_fw = 2 * tan(verticalAngle / 2.0) * curFocalDistance; kf_fh = fw / kf->getCameraViewAspect(); } else { double height = kf->getCameraHeightField(); double aspect = kf->getCameraViewAspect(); double width = height * aspect; kf_fw = width; kf_fh = height; } pFieldsAction->setKeypoint(kftl, OdTvAnimationAction::kScaleX, kf_fw / fw, OdTvAnimationAction::kLinear); pFieldsAction->setKeypoint(kftl, OdTvAnimationAction::kScaleY, kf_fh / fh, OdTvAnimationAction::kLinear); OdTvVector kf_up = matr.getCsYAxis(); pUpAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationX, kf_up.x - up.x, OdTvAnimationAction::kLinear); pUpAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationY, kf_up.y - up.y, OdTvAnimationAction::kLinear); pUpAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationZ, kf_up.z - up.z, OdTvAnimationAction::kLinear); } { OdTvSubItemPath actor; actor.entitiesIds().push_back(cameraId); actor.geometryDatasIds().push_back(pCamera->targetId()); pContainer->addAnimation(actor, targetActionId, 0); } { OdTvSubItemPath actor; actor.entitiesIds().push_back(cameraId); actor.geometryDatasIds().push_back(pCamera->positionId()); pContainer->addAnimation(actor, positionActionId, 0); } { OdTvSubItemPath actor; actor.entitiesIds().push_back(cameraId); actor.geometryDatasIds().push_back(pCamera->fieldsId()); pContainer->addAnimation(actor, fieldsActionId, 0); } { OdTvSubItemPath actor; actor.entitiesIds().push_back(cameraId); actor.geometryDatasIds().push_back(pCamera->upId()); pContainer->addAnimation(actor, upActionId, 0); } pCamera->assignView(newViewId); return true; } bool OdTvNwSavedAnimationEnumerator::collectSelectAnim(const OdNwSavedAnimSelectAnim * pSelectAnim) { OdNwObjectIdArray ObjIdList; ObjIdList = pSelectAnim->getModelItem(); return true; } void matr2Angles(OdGeMatrix3d& R, double& x, double& y, double& z) { if (!OdEqual(R[2][0], 1.) && !OdEqual(R[2][0], -1.)) { double pitch_1 = -1. * asin(R[2][0]); double pitch_2 = OdaPI - pitch_1; double cosPitch1 = cos(pitch_1); double cosPitch2 = cos(pitch_2); ODA_ASSERT(!OdEqual(cosPitch1, 0.)); ODA_ASSERT(!OdEqual(cosPitch2, 0.)); double roll_1 = atan2(R[2][1] / cosPitch1, R[2][2] / cosPitch1); double roll_2 = atan2(R[2][1] / cosPitch2, R[2][2] / cosPitch2); double yaw_1 = atan2(R[1][0] / cosPitch1, R[0][0] / cosPitch1); double yaw_2 = atan2(R[1][0] / cosPitch2, R[0][0] / cosPitch2); if (OdLessOrEqual(std::abs(roll_1) + std::abs(pitch_1) + std::abs(yaw_1), std::abs(roll_2) + std::abs(pitch_2) + std::abs(yaw_2))) { y = pitch_1; x = roll_1; z = yaw_1; return; } else { y = pitch_2; x = roll_2; z = yaw_2; return; } } else { z = 0; // anything(we default this to zero) if (OdEqual(R[2][0], -1.)) { y = OdaPI2; x = z + atan2(R[0][1], R[0][2]); } else { y = -OdaPI2; x = -1. * z + atan2(-1. * R[0][1], -1. * R[0][2]); } } } bool OdTvNwSavedAnimationEnumerator::enumSelectAnim(const OdNwSavedAnimSelectAnim * pSelectAnim) { OdTvResult er = tvOk; if (!pSelectAnim) { return false; } OdTvDevicesIteratorPtr pDevIt = m_pTvDb->getDevicesIterator(); OdTvGsDevicePtr pDevice = pDevIt->getDevice().openObject(OdTv::kForWrite); OdTvGsViewId originalViewId = pDevice->viewAt(0); OdTvGsViewPtr pOriginalView = originalViewId.openObject(OdTv::kForWrite); OdNwObjectIdArray ObjIdList; if (!pSelectAnim || pSelectAnim->getChildren(ObjIdList) != eOk) { return false; } auto keyFrameComparFn = [](const OdNwSavedAnimSelectKeyFramePtr & a, const OdNwSavedAnimSelectKeyFramePtr & b) { return a->getTime() < b->getTime(); }; std::set setKeyFrame(keyFrameComparFn); for (auto & sceneChildId : ObjIdList) { OdNwSavedAnimSelectKeyFramePtr pAnimSelectKeyFrame = OdNwSavedAnimSelectKeyFrame::cast(sceneChildId.safeOpenObject()); setKeyFrame.insert(pAnimSelectKeyFrame); } OdNwSavedAnimSelectKeyFramePtr firstKf = *setKeyFrame.begin(); OdNwSavedAnimSelectKeyFramePtr lastKf = *setKeyFrame.rbegin(); double kps = 24; double lastKfTime = lastKf->getTime(); int totalKfnum = ceil(lastKfTime*kps) + 1; OdTvAnimationContainerId contId = m_pTvDb->createAnimationContainer(pSelectAnim->getDisplayName()); OdTvAnimationContainerPtr pContainer = contId.openObject(OdTv::kForWrite); OdTvAnimationActionId translateActionId = m_pTvDb->createAnimationAction(OD_T("TranslateAction") + pSelectAnim->getDisplayName()); OdTvAnimationActionPtr pTranslateAction = translateActionId.openObject(OdTv::kForWrite); pTranslateAction->setFPS(kps); pTranslateAction->setNumFrames(totalKfnum); OdGePoint3d firstPos; OdGePoint3d centerPoint; OdGeVector3d scaleVec; OdGeQuaternion rotationQuat; OdGeVector3d newTransl; for (OdNwSavedAnimSelectKeyFramePtr kf : setKeyFrame) { double kfTime = kf->getTime(); int kftl = ceil(kfTime * kps); OdGePoint3d newCenter = kf->getCenter(); centerPoint = newCenter; if (kf->isPropertyStored(NwSavedAnimSelectKeyFramePropKind::TRANSLATION)) { newTransl = kf->getTranslation(); } if (kf->isPropertyStored(NwSavedAnimSelectKeyFramePropKind::SCALE)) { scaleVec = kf->getScaleVector(); } if (kf->isPropertyStored(NwSavedAnimSelectKeyFramePropKind::ROTATION)) { rotationQuat = kf->getRotation(); } // don't delete // need for checking bug/nws-1271 its avoiding conditional reading translation/scale/rotation // //newTransl = kf->getTranslation(); //scaleVec = kf->getScaleVector(); //rotationQuat = kf->getRotation(); OdGeMatrix3d rotationMatr = rotationQuat.normalize().getMatrix(); double rollX, pitchY, yawZ; matr2Angles(rotationMatr, rollX, pitchY, yawZ); auto normalRotateDeg = [](double a) -> double { if (OdGreaterOrEqual(a, 180.0)) { double m = std::floor((a - 180.0) / 360.0) + 1; a = a - m * 360.0; // expalantion of conversion //while (OdGreaterOrEqual(a, 180.0)) //{ // a -= 360.0; //} } else if (OdLess(a, .0)) { double m = std::floor(abs(a) / 360.0) + 1; a = a + m * 360.0; //while (OdLess(a, .0)) //{ // a += 360.0; //} } return a; }; double rollXdeg = OdaToDegree(rollX); double pitchYdeg = OdaToDegree(pitchY); double yawZdeg = OdaToDegree(yawZ); double rollXdegNorm = normalRotateDeg(rollXdeg); double pitchYdegNorm = normalRotateDeg(pitchYdeg); double yawZdegNorm = normalRotateDeg(yawZdeg); double rollXradNorm = OdaToRadian(rollXdegNorm); double pitchYradNorm = OdaToRadian(pitchYdegNorm); double yawZradNorm = OdaToRadian(yawZdegNorm); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationX, newTransl.x - firstPos.x, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationY, newTransl.y - firstPos.y, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kTranslationZ, newTransl.z - firstPos.z, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kScaleX, scaleVec.x, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kScaleY, scaleVec.y, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kScaleZ, scaleVec.z, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationX, rollXradNorm, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationY, pitchYradNorm, OdTvAnimationAction::kLinear); pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationZ, yawZradNorm, OdTvAnimationAction::kLinear); // don't delete // need for checking bug/nws-1271 its avoiding normalisation if rotation values // //pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationX, rollX, OdTvAnimationAction::kLinear); //pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationY, pitchY, OdTvAnimationAction::kLinear); //pTranslateAction->setKeypoint(kftl, OdTvAnimationAction::kRotationZ, yawZ, OdTvAnimationAction::kLinear); } std::function< void(const OdNwObjectId&, std::function, OdTvSubItemPath*)> setAnimationByPath = [this, &setAnimationByPath]( const OdNwObjectId& nwObjId, std::function addAnimationToContainer, OdTvSubItemPath* pParents ) { OdNwModelItemPtr pMI = nwObjId.openObject(); OdTvSubItemPath tvSubPath; OdTvMatrix parentTrm = OdTvMatrix::kIdentity; if (pParents) tvSubPath = *pParents; else { OdNwObjectIdArray aAncestors; pMI->getAncestors(aAncestors); for (auto& ancId : aAncestors) { auto resFnd = m_NwOIds2TvIdsMap.find(ancId); //find if there is tv object for this nw model item if (resFnd != m_NwOIds2TvIdsMap.end()) { //if model item has tv entity id interpretation - add it to tvsubpath and get transformation from this // second is tuple if (!std::get<0>(resFnd->second).isNull()) { tvSubPath.entitiesIds().push_back(std::get<0>(resFnd->second)); if (std::get<0>(resFnd->second).getType() == OdTvEntityId::EntityTypes::kEntity) { auto trm = std::get<0>(resFnd->second).openObject()->getModelingMatrix(); //if entity has transformation - apply it to full parent transformation, this is need for animation basis if (trm != OdTvMatrix::kIdentity) parentTrm.postMultBy(trm); } else if (std::get<0>(resFnd->second).getType() == OdTvEntityId::EntityTypes::kInsert) { // if parent object is insert - replace all parent transform by this, // because in nw2visualize all inserts are added into tvmodel and // already has parent transform in block transformation parentTrm = std::get<0>(resFnd->second).openObjectAsInsert()->getBlockTransform(); } } //if model item has tv sub entity id interpretation - add it to tvsubpath and get transformation from this else if (!std::get<1>(resFnd->second).isNull()) { tvSubPath.geometryDatasIds().push_back(std::get<1>(resFnd->second)); if (std::get<1>(resFnd->second).getType() == OdTv::OdTvGeometryDataType::kSubEntity) { auto trm = std::get<1>(resFnd->second).openAsSubEntity()->getModelingMatrix(); //if entity has transformation - apply it to full parent transformation, this is need for animation basis if (trm != OdTvMatrix::kIdentity) parentTrm.postMultBy(trm); } } } } } //find if there is tv object for this nw model item auto resFnd = m_NwOIds2TvIdsMap.find(nwObjId); if (resFnd != m_NwOIds2TvIdsMap.end()) { if (!std::get<0>(resFnd->second).isNull()) { //if there is tv entity id interpretation for this model item - add it to sub path and add to animation container tvSubPath.entitiesIds().push_back(std::get<0>(resFnd->second)); addAnimationToContainer(tvSubPath, parentTrm); return; } else if (!std::get<1>(resFnd->second).isNull()) { //if there is tv sub entity id interpretation for this model item - add it to sub path and add to animation container tvSubPath.geometryDatasIds().push_back(std::get<1>(resFnd->second)); addAnimationToContainer(tvSubPath, parentTrm); return; } } //if this model item hasn't tv object interpretation - try to find if it's children has OdNwObjectIdArray aChildren; if (pMI->getChildren(aChildren) == eOk) { for (auto& chId : aChildren) setAnimationByPath(chId, addAnimationToContainer, &tvSubPath); } }; auto objList = pSelectAnim->getModelItem(); for (auto & mi : objList) { setAnimationByPath(mi, [¢erPoint, &pContainer, &translateActionId](OdTvSubItemPath& actor, const OdTvMatrix& trm) { OdTvAnimationContainer::OdTvActorBasis basis(centerPoint); //if entity is added to tv model - it's possible add animation with 'forcetransform' if(actor.geometryDatasIds().empty() && !actor.entitiesIds().empty() && actor.entitiesIds()[ 0 ].getType() == OdTvEntityId::kEntity ) { pContainer->addAnimation( actor, translateActionId, 0, 0, &basis, true ); } else { if (trm == OdTvMatrix::kIdentity) { pContainer->addAnimation(actor, translateActionId, 0); } else { //if parents of this entity has transformation - need to set them as new actor basis OdTvAnimationContainer::OdTvActorBasis actorBasis(trm.getCsOrigin(), trm.getCsXAxis(), trm.getCsYAxis(), trm.getCsZAxis()); pContainer->addAnimation(actor, translateActionId, 0, 0, &actorBasis); } } }, nullptr); } return true; } void OdTvNwSavedAnimationEnumerator::enumSceneChild(const OdNwSavedItem * pSceneChild) { if (pSceneChild) { if (pSceneChild->isA() == OdNwSavedAnimSelectAnim::desc()) { enumSelectAnim(OdNwSavedAnimSelectAnim::cast(pSceneChild)); } else if (pSceneChild->isA() == OdNwSavedAnimFolder::desc()) { OdNwObjectIdArray folderChildren; if (OdNwSavedAnimFolder::cast(pSceneChild)->getChildren(folderChildren) == eOk) { for (OdNwObjectId item : folderChildren) { OdNwSavedItemPtr psi = item.openObject(); enumSceneChild(psi); } } } else if (pSceneChild->isA() == OdNwSavedAnimClip::desc()) { } else if (pSceneChild->isA() == OdNwSavedAnimCamera::desc()) { enumAnimGroup(OdNwSavedAnimGroup::cast(pSceneChild)); } } }; void OdTvNwSavedAnimationEnumerator::enumAnimScene(const OdNwSavedAnimScene * pScene) { OdNwObjectIdArray sceneChildIdList; if (pScene && pScene->getChildren(sceneChildIdList) == eOk) { for (auto & sceneChildId : sceneChildIdList) { enumSceneChild(OdNwSavedItem::cast(sceneChildId.safeOpenObject())); } } }; void OdTvNwSavedAnimationEnumerator::enumAnimSceneFolder (const OdNwSavedAnimSceneFolder * pSceneFolder) { ODA_ASSERT(pSceneFolder); OdNwObjectIdArray ObjIdList;; pSceneFolder->getChildren(ObjIdList); for (auto& item : ObjIdList) { enumAnimScene(OdNwSavedAnimScene::cast(item.safeOpenObject())); }; }; void OdTvNwSavedAnimationEnumerator::enumAnimation() { if (m_nwSavedAnimationId.isNull()) { return; } OdNwSavedAnimElementPtr pSavedAnimElem = m_nwSavedAnimationId.safeOpenObject(); OdNwObjectIdArray savedItemIdList; if (pSavedAnimElem->getSavedItems(savedItemIdList) == eOk) { for (auto& item : savedItemIdList) { OdNwSavedItemPtr pItem = item.safeOpenObject(); if (!pItem.isNull()) { if (pItem->isKindOf(OdNwSavedAnimScene::desc())) { enumAnimScene(OdNwSavedAnimScene::cast(pItem)); } else if (pItem->isKindOf(OdNwSavedAnimSceneFolder::desc())) { enumAnimSceneFolder(OdNwSavedAnimSceneFolder::cast(pItem)); } } } } } void OdTvNwSavedAnimationEnumerator::feedAnimation() { m_cameraCount = 0; enumAnimation(); }