UserData Parent Group's Level?



  • On 30/01/2017 at 08:41, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R13 
    Platform:   Windows  ;   
    Language(s) :     C++  ;   PYTHON  ;

    ---------
    Hi,
    I'm have a devil of a time getting the correct parent of each UD item using DESC_PARENTGROUP.
    It returns a DescID type value, and for life of me I cannot extract the values from it. 😠
    I need the first value. That's the level# for the UD item's parent. But I just cannot get it.

    These are the things I've tried so far.
    This is written in Python because it's quicker to play around with. But I need to get the parent's level#s in C++ as well as in Python.
    How the heck do we get the values from DESC_PARENTGROUP?

    import c4d  
    def main() :  
        
      obj = doc.GetActiveObject()  
      if obj is None: return    
        
      for UD_ID, bc in obj.GetUserDataContainer() :             
           
          pgroup = bc[c4d.DESC_PARENTGROUP]          
                    
          #This prints the correct group the UD entry belongs to   
          #But it's returned in a DescID format. example: (5,1,0)  
          print pgroup   
            
          #This prints c4d.DescLevel object at hex number  
          #How do I use that?  
          print pgroup[0]  
            
          #This prints (700, 5, 0) for all UD items!?  
          print pgroup[0].id  
            
          #This also returns incorrect values  
          #It prints (700, 5, 0) for every UD item!?   
          print c4d.DescID(pgroup[0])          
            
          #This also returns incorrect values  
          #It prints (700, 0, 0) for every UD item!?          
          ID = c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA, c4d.DTYPE_SUBCONTAINER, 0), c4d.DescLevel(pgroup[0].id))   
          print ID  
            
          #How do I get the correct first value of the pgroup DescID object??          
        
      c4d.EventAdd()      
      
    if __name__=='__main__':  
      main()
    

    -ScottA



  • On 30/01/2017 at 10:23, xxxxxxxx wrote:

    I found some code in the new R18 docs that helped me figure out how to do this in C++.
    But there's a gotcha in the docs. The docs say that DESC_PARENTGROUP is a LONG data type. So logically you would assign a LONG variable to it. But that's wrong.
    You actually need to use GeData then get the LONG value from that.
    That is not explained anywhere in the docs!!!

    This is an example how to get the parent group's level# from the UD item at level# 6
    This can be used to determine which group the #6 UD item belongs to

        BaseObject *obj = doc->GetActiveObject();  
      if (!obj) return false;  
      
      DynamicDescription *ud = obj->GetDynamicDescription();  
      
      DescID item(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), 6);  //Find the specific UserData entry using it's level#  
      const BaseContainer *data = ud->Find(item);                     //Get the data for this specific UD item  
      
      String name = data->GetString(DESC_NAME);                //Get the name of the UD item  
      LONG type = data->GetLong(DESC_CUSTOMGUI);               //Get the data type   
      LONG unit = data->GetLong(DESC_UNIT);                    //Get the units setting(Real, Percent. etc..)  
      GeData parentId = data->GetData(DESC_PARENTGROUP);       //WARNING!! docs say to use LONG here!!!!  
      GePrint(name);  
      GePrint(LongToString(type));  
      GePrint(LongToString(unit));  
      
      //Get the value for the gizmo if it's the correct type   
      if (type == CUSTOMGUI_REALSLIDER)  
      {          
          GeData d;  
          obj->GetParameter(item, d, DESCFLAGS_GET_0);  
          Real value = d.GetReal();  
          GePrint(RealToString(value));  
      }  
      
      //This gets the level# of the parent UD group this UD item is a child of  
      //If there is no parent group. It returns the default group(700)  
      if (parentId.GetType() == CUSTOMDATATYPE_DESCID)  
      {  
          CustomDataType *customData = parentId.GetCustomDataType(CUSTOMDATATYPE_DESCID);  
          const DescID *descID = static_cast<const DescID*>(customData);  
          if (descID)  
          {  
              LONG id = descID->operator[](-1).id;  
              GePrint("Parent Group ID: " + LongToString(id));  
          }  
      }
    

    Any ideas how I can do the same thing in Python?

    -ScottA



  • On 31/01/2017 at 01:25, xxxxxxxx wrote:

    Hello,

    the DESC_PARENTGROUP value is a DescID. You find an example on how to obtain it in the Description Settings Manual.

    You can obtain the actual ID in Python in the same way. Using BaseContainer.GetData() you can obtain the DescID. From that DescID you can obtain the fist DescLevel. Then you can access that DescLevel's "id" member.

      
    descID = bc.GetData(c4d.DESC_PARENTGROUP)  
    ID = descID[0].id  
    print(str(ID))  
    

    best wishes,
    Sebastian



  • On 31/01/2017 at 07:34, xxxxxxxx wrote:

    Hi Sebastian,

    That code returns the default parent every time (700) instead of the actual groups that exist in the UserData.
    I'm using R13. Could that make a difference?

    import c4d  
    def main() :  
        
      obj = doc.GetActiveObject()  
      if obj is None: return      
      
      for UD_ID, bc in obj.GetUserDataContainer() :  
            
          #This gets the correct values of the parents  
          #But it's locked up in a description  
          print bc.GetData(c4d.DESC_PARENTGROUP)          
            
          #This gets the wrong parent values (all 700's)  
          descID = bc.GetData(c4d.DESC_PARENTGROUP)  
          ID = descID[0].id  
          #print "parent: ", (str(ID))  #<--- prints 700 when it should not!?  
            
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    -ScottA

    -Edit:
    I figured it out. I was only getting the first DescLevel for each instance of DescID.
    Each parent group (DescID) can have a different number of DescLevels in it depending if it's a Group or not a Group. So getting the correct amount of return values from them is a bit of a challenge.
    This is the code I came up with. It works. But it's ridiculously complex and ugly.
    So if there's a better way to write this please let me know:

    import c4d  
    def main() :  
        
      obj = doc.GetActiveObject()  
      if obj is None: return  
        
      for UD_ID, bc in obj.GetUserDataContainer() :  
              
          level = UD_ID[1].id          
          item_name = bc.GetString(c4d.DESC_NAME)      
      
          #The descID that holds (stackPos, dType, creator)   
          descID = bc.GetData(c4d.DESC_PARENTGROUP)  
            
          #To extract the parent (stackPos) out of this descID,  
          #I have to do some rather crazy codeing gymnastics                  
      
          #A UD Group return less DescLevels than a non UD Group  
          #A Group UD item returns a length of 1  
          #A non Group UD item returns a length of 2  
          numData = len(descID)  
            
          #So I need to test the length of each UD item's descID  
          #If I don't do this...I get unwanted repeating ouput values   
          if numData == 1:  
               for i in xrange(len(descID)) :  
                   if i == 0:   
                       print "Group: ", item_name  
                     
          if numData == 2:  
               for i in xrange(len(descID)) :  
                   if i == 1: print "Not A Group: " , item_name    
        
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    -Edit #2:
    Nope. Still not working properly.
    Why is it so damned  difficult to loop through the UD items and get the parent they belong to?
    I'm getting angry now. Angry

    -Edit #3
    OK. Let's try this one for a while and see if it breaks.😂
    I'm leaving all of my previous code attempts here so you can see how badly I'm struggling.
    This should have been a simple task. But it's been a total nightmare.

    import c4d  
    def main() :  
        
      obj = doc.GetActiveObject()  
      if obj is None: return  
        
      for UD_ID, bc in obj.GetUserDataContainer() :  
              
          level = UD_ID[1].id          
          item_name = bc.GetString(c4d.DESC_NAME)      
      
          #The descID that holds (stackPos, dType, creator)   
          descID = bc.GetData(c4d.DESC_PARENTGROUP)  
            
          #More goofy code to extract the parent of each UD item  
          if len(descID) == 1: print descID[0].id, item_name  
          if len(descID) != 1: print descID[1].id, item_name  
        
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    -ScottA



  • On 01/02/2017 at 00:10, xxxxxxxx wrote:

    Hello,

    you can access the last DescLevel stored in a DescID using the index "-1". See the DescID Manual.

    best wishes,
    Sebastian



  • On 01/02/2017 at 07:13, xxxxxxxx wrote:

    Thanks Sebastian.
    Using descID[-1].id seems to work the exact same was as my invented code:
          #Extract the parent of each UD item
          if len(descID) == 1: print descID[0].id
          if len(descID) != 1: print descID[1].id
    But it's much more elegant.

    Thanks for the help,
    ScottA


Log in to reply