Finding Stuff by MItDag

This note is about how to find stuff in Maya API.

Sometimes we need to find the specific object in the scene by its name. Here is a very crude way to do that:

MItDag itdag(MItDag::kDepthFirst); 
for(; !itdag.isDone(); itdag.next()) 
{ 
  MFnDagNode pf(itdag.currentItem()); 
  if(pf.fullPathName() == MString(name)) 
  { 
    return itdag.currentItem(); 
  } 
} 
return MObject::kNullObj;

The DAG iterator starts as the world root, the traverses through every available DAG node, comparing the pall path name of the node with given name. It returns the MObject if hits a match. For example: to find sphere1 under group1, which is under group2, we should give “|group2|group1|sphere1” to match.

It is quite a wasteful way to find a node in case there are lots of them out there, traversing to right end of them can take some time. I think the searching process can be benefit from the hierarchical nature of the notes. In other words: if |group2 does not exist, |group2|group1 and |group2|group1|sphere1, or everything possibly under |group2 won’t exist either. So we search |group2 first. If found, reset the iterator to |group2, looking for |group2|group1. If found, reset to where we found and search for the next one under it. Anytime the search returns nothing, time to abort. The improved method is:

char findChildByName(MObject &parent, MObject &result, std::string &name)
{
 MItDag itdag(MItDag::kBreadthFirst);
 
 if(parent != MObject::kNullObj)
   itdag.reset(parent);
 
 for(; !itdag.isDone(); itdag.next())
 {
   MFnDagNode pf(itdag.currentItem());
   if(pf.fullPathName() == MString(name.c_str())) 
   {
     result = itdag.currentItem();
     return 1;
   }
 }
 result = MObject::kNullObj;
 return 0;
}

char AHelper::getObjByFullName(const char* name, MObject& res)
{
 std::string r;
 std::string str = name;
 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 boost::char_separator<char> sep("|");
 tokenizer tokens(str, sep);
 MObject parent = MObject::kNullObj;
 for (tokenizer::iterator tok_iter = tokens.begin();
 tok_iter != tokens.end(); ++tok_iter)
 {
   r = r + "|" + (*tok_iter);
   if(!findChildByName( parent, res, r))
   return 0;
 
   parent = res;
 }
 return 1;
}

The traversal type of the iterator is set to breadth-first, so it will jump to next sibling instead of wasting time on the children of an unmatched node.

Advertisements

Leave a comment

Filed under Maya API

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s