#include "GroupPrimsCommand.h" #include "../../utils/Logger.h" #include #include #include PXR_NAMESPACE_USING_DIRECTIVE namespace UsdLayerManager { GroupPrimsCommand::GroupPrimsCommand(UsdStageRefPtr stage, const std::vector& srcPaths, const SdfPath& groupPath) : m_stage(stage) , m_groupPath(groupPath) , m_srcPaths(srcPaths) , m_description("Group " + std::to_string(srcPaths.size()) + " prim(s) under " + groupPath.GetString()) { } /// Compute a unique child name under @p parent (collision check against live stage). static std::string UniqueNameUnder(UsdStageRefPtr stage, const SdfPath& parent, const std::string& baseName) { std::string name = baseName; int n = 1; while (stage->GetPrimAtPath(parent.AppendChild(TfToken(name))).IsValid()) name = baseName + "_" + std::to_string(n++); return name; } static UsdPrim GetParentPrim(UsdStageRefPtr stage, const SdfPath& parentPath) { if (parentPath == SdfPath("/") || parentPath == SdfPath::AbsoluteRootPath()) return stage->GetPseudoRoot(); return stage->GetPrimAtPath(parentPath); } void GroupPrimsCommand::Execute() { // Create the Xform group. UsdPrim groupPrim = m_stage->DefinePrim(m_groupPath, TfToken("Xform")); if (!groupPrim.IsValid()) { LOG_ERROR("GroupPrimsCommand::Execute: failed to create group: " + m_groupPath.GetString()); return; } m_movedNames.clear(); for (const SdfPath& srcPath : m_srcPaths) { UsdPrim src = m_stage->GetPrimAtPath(srcPath); if (!src.IsValid()) { LOG_WARNING("GroupPrimsCommand::Execute: prim not found (skipping): " + srcPath.GetString()); m_movedNames.emplace_back(srcPath.GetName()); continue; } // Compute a collision-free name inside the group. std::string name = UniqueNameUnder(m_stage, m_groupPath, srcPath.GetName()); m_movedNames.push_back(name); UsdPrim gPrim = m_stage->GetPrimAtPath(m_groupPath); UsdNamespaceEditor editor(m_stage); editor.ReparentPrim(src, gPrim, TfToken(name)); std::string whyNot; if (!editor.CanApplyEdits(&whyNot)) { LOG_ERROR("GroupPrimsCommand::Execute: cannot reparent " + srcPath.GetString() + ": " + whyNot); continue; } if (!editor.ApplyEdits()) { LOG_ERROR("GroupPrimsCommand::Execute: ApplyEdits failed for " + srcPath.GetString()); } } } void GroupPrimsCommand::Undo() { if (m_movedNames.size() != m_srcPaths.size()) { LOG_ERROR("GroupPrimsCommand::Undo: state mismatch, cannot undo safely"); return; } // Reparent children back in reverse order. for (int i = (int)m_srcPaths.size() - 1; i >= 0; --i) { SdfPath movedPath = m_groupPath.AppendChild(TfToken(m_movedNames[i])); UsdPrim moved = m_stage->GetPrimAtPath(movedPath); if (!moved.IsValid()) { LOG_WARNING("GroupPrimsCommand::Undo: prim not in group (skipping): " + movedPath.GetString()); continue; } SdfPath origParentPath = m_srcPaths[i].GetParentPath(); UsdPrim origParent = GetParentPrim(m_stage, origParentPath); if (!origParent.IsValid()) { LOG_ERROR("GroupPrimsCommand::Undo: original parent not found: " + origParentPath.GetString()); continue; } UsdNamespaceEditor editor(m_stage); editor.ReparentPrim(moved, origParent, TfToken(m_srcPaths[i].GetName())); std::string whyNot; if (!editor.CanApplyEdits(&whyNot)) { LOG_ERROR("GroupPrimsCommand::Undo: cannot reparent back " + movedPath.GetString() + ": " + whyNot); continue; } if (!editor.ApplyEdits()) { LOG_ERROR("GroupPrimsCommand::Undo: ApplyEdits failed for " + movedPath.GetString()); } } // Remove the (now empty) group prim. m_stage->RemovePrim(m_groupPath); } } // namespace UsdLayerManager