Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Iterate

    PYTHON Development
    0
    38
    24.4k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 03/06/2017 at 02:59, xxxxxxxx wrote:

      Is there a way for getting the bc of individual user data without hte need to loop?

      Like something liek that but without the loop wich is really not efficiency at all.

      import c4d
        
      def main() :
        if op is None: return
        
        desc_id, bc = get_bc(4)
        op[desc_id] = bc[c4d.DESC_DEFAULT]
        c4d.EventAdd()
        
      def get_bc(my_id) :
          for id, bc in op.GetUserDataContainer() :
              if id[-1].id == my_id:
                  return id, bc
        
      if __name__=='__main__':
        main()
      
      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 03/06/2017 at 04:26, xxxxxxxx wrote:

        I posted a file which may help.
        https://www.dropbox.com/s/s264ofllrr7pq1d/reset test.c4d?dl=0

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 03/06/2017 at 08:38, xxxxxxxx wrote:

          GetUserDataContainer() over and over again is pretty slow. Call it once and reuse the result.

          ud = op.GetUserDataContainer()
          desc_id, bc = get_bc(ud, 4)
          

          To optimize the loop to find the matching entry, you can build a dictionary first.

          ud = {}
          for id, bc in op.GetUserDataContainer() :
            ud[id[-1].id] = (id, bc)
            
          desc_id, bc = ud[4]
          
          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 03/06/2017 at 08:57, xxxxxxxx wrote:

            Yes it's what I did but I fel not optimized.
            I should not post on c4dcafe but only here.
            So to the op I will stop the answerd on the c4d cafee 😉

            https://www.c4dcafe.com/ipb/forums/topic/98566-easier-iteration/#comment-652009

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 03/06/2017 at 11:35, xxxxxxxx wrote:

              Originally posted by xxxxxxxx

              Is there a way for getting the bc of individual user data without hte need to loop?

              Yes.
              You can get the data for a specific UD item by either it's ID#. Or by it's position within the UD stack.
              Here's an example of getting a specific UD item by it's ID# in the UD manager:

              import c4d  
              def main() :  
                  
                if op is None: return  
                  
                index = 1  #<---Change the target UD item as desired  
                  
                ud = op.GetUserDataContainer()  
                item = ud[index-1]    
                bc = item[1]  
                name = bc.GetString(c4d.DESC_NAME)   
                udType = bc.GetLong(c4d.DESC_CUSTOMGUI)   
                units = bc.GetLong(c4d.DESC_UNIT)   
                  
                #If the UD item is not a Group...Get it's value  
                if udType != 0:   
                  item_value = op[c4d.ID_USERDATA, index]  
                  print item_value  
                
                c4d.EventAdd()  
                
              if __name__=='__main__':  
                main()
              

              -ScottA

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 03/06/2017 at 12:10, xxxxxxxx wrote:

                Thanks you scotta ! I didn't thinked about the -1 and was baited with this ! 😄 I learned something thanks you.

                Anyway here I guess is the most optimized thing we can do.
                Code to be into the Tag object.

                #Scotta win the optimization contest ! :p
                #https://developers.maxon.net/forum/topic/483/13629_iterate
                import c4d
                  
                def reset(obj, id_reset, list_id, ud_bc) :
                    #Only if reset is True
                    if obj[c4d.ID_USERDATA, id_reset]:
                        obj[c4d.ID_USERDATA, id_reset] = False
                        
                        #We list all our id who are into our list_of_id_to_reset
                        for id in list_id:
                            if id == id_reset:
                                continue
                            
                            #Get the data corresponding to the user data bc
                            item = ud_bc[id_reset-1]
                            descid = item[0]
                            bc = item[1]
                            try:
                                obj[descid] = bc[c4d.DESC_DEFAULT]
                            except:
                                pass
                                                        
                            
                def main() :
                    #Get the object attached ot the tag
                    obj = op.GetObject()
                    
                    #Get the userData Object
                    ud_bc = obj.GetUserDataContainer()
                    
                    #list who store all our data
                    #Reset_id, List_of_id_to_reset, list_of_descid_bc
                    datas = list()
                  
                    #Data exemple for G_Vegas
                    #prefer tuples since they are speeder than list
                    tuple_G_vegas = (486, 15, 17, 4, 44, 42, 27, 28, 512, 36, 29, 393, 38, 39, 40, 19, 389)
                    datas.append([486, tuple_G_vegas])
                  
                    #Loop for each data then reset them
                    for data in datas:
                        reset(obj, data[0], data[1], ud_bc)
                        
                    #Trigger c4d update
                    c4d.EventAdd()
                  
                  
                if __name__ == '__main__':
                    main()
                

                And the code for generate tuple of all id under parent

                import c4d
                  
                def get_all_children_ud(obj, list_all_children, parent_id) :
                    ignore_list = [c4d.DTYPE_GROUP,
                                   c4d.DTYPE_SEPARATOR]
                                   
                    for id, bc in obj.GetUserDataContainer() :
                        if bc[c4d.DESC_PARENTGROUP][-1].id == parent_id:
                            desc_level = id[-1]
                            if not desc_level.dtype in ignore_list:
                                list_all_children.append(desc_level.id)
                  
                def main() :
                    obj = doc.GetActiveObject()
                    if not obj:
                        return
                    
                    list_all_children = list()
                    parent_id = 284
                    
                    get_all_children_ud(obj, list_all_children, parent_id)
                    print tuple(list_all_children)
                    
                  
                if __name__=='__main__':
                    main()
                

                EDIT: Hooww didn't work in the op exemple since the user id stack is not build from scratch and got some missing id 😕 So I guess my previous method was correct.

                import c4d
                  
                #dict who gonna store all our bc and descid. Like that we iterate only 1 time.
                #dict["user_data_id"] = [descid, bc]
                #I use global vairable liek that we only have to do build it one time.
                #take care if you add/remove ud you need to update it, look the main function
                global dict_descid_bc
                dict_descid_bc = None
                  
                def reset(obj, id_reset, list_id) :
                    global dict_descid_bc
                    ud_bc = obj.GetUserDataContainer()
                    
                    #Only if reset is True
                    if obj[c4d.ID_USERDATA, id_reset]:
                        obj[c4d.ID_USERDATA, id_reset] = False
                        #We list all our id who are into our list_of_id_to_reset
                        for id in list_id:
                            if id == id_reset:
                                continue
                            
                            descid = dict_descid_bc[str(id)][0]
                            bc = dict_descid_bc[str(id)][1]
                            try:
                                obj[descid] = bc[c4d.DESC_DEFAULT]
                            except:
                                pass
                                    
                def get_descid_bc(obj, dict) :
                    for descid, bc in obj.GetUserDataContainer() :
                        dict[str(descid[-1].id)] = [descid, bc]
                                    
                            
                def main() :
                    #Get the object attached ot the tag
                    obj = op.GetObject()
                    
                    #Tell to python we use the global variable
                    global dict_descid_bc
                    
                    #Only update our dict if not build yet.
                    if not dict_descid_bc:
                        dict_descid_bc = dict()
                        get_descid_bc(obj, dict_descid_bc)
                    
                    #list who store all our data
                    #Reset_id, List_of_id_to_reset, list_of_descid_bc
                    datas = list()
                  
                    #Data exemple for G_Vegas
                    tupe_G_vegas = (486, 15, 17, 4, 44, 42, 27, 28, 512, 36, 29, 393, 38, 39, 40, 19, 389)
                    datas.append([486, tupe_G_vegas ])
                  
                    #Loop for each data then reset them
                    for data in datas:
                        reset(obj, data[0], data[1])
                        
                    #Trigger c4d update
                    c4d.EventAdd()
                  
                  
                if __name__ == '__main__':
                    main()
                
                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 03/06/2017 at 14:29, xxxxxxxx wrote:

                  Tested in the scene file and the code above does not work. The code previous to that will throw the reset switch but none of the user data is reset to default.
                  Here is a link to the file with all the code on separate tags, only the latest enabled.

                  https://www.dropbox.com/s/s264ofllrr7pq1d/reset test.c4d?dl=0

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 03/06/2017 at 16:39, xxxxxxxx wrote:

                    @ScottA that's not always going to work since the IDs are not garuanteed to be continous (delete a userdata) or in orde (re-order parameters). Hence my proposal with the dictionary.

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 03/06/2017 at 18:26, xxxxxxxx wrote:

                      I never said that it was the proper solution to use Niklas.
                      I merely answered his question on "if there was a way to target a specific UD item without using a loop".
                      I never told him to use it. Nor did I tell him it was a better solution than yours.

                      -ScottA

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 04/06/2017 at 00:45, xxxxxxxx wrote:

                        import c4d
                          
                        #dict who gonna store all our bc and descid. Like that we iterate only 1 time.
                        #dict["user_data_id"] = [descid, bc]
                        #I use global vairable liek that we only have to do build it one time.
                        #take care if you add/remove ud you need to update it, look the main function
                        global dict_descid_bc
                        dict_descid_bc = None
                          
                        def reset(obj, id_reset, list_id) :
                            global dict_descid_bc
                            ud_bc = obj.GetUserDataContainer()
                            
                            #Only if reset is True
                            if obj[c4d.ID_USERDATA, id_reset]:
                                obj[c4d.ID_USERDATA, id_reset] = False
                                #We list all our id who are into our list_of_id_to_reset
                                for id in list_id:
                                    if id == id_reset:
                                        continue
                                    
                                    descid = dict_descid_bc[id][0]
                                    bc = dict_descid_bc[id][1]
                                    try:
                                        obj[c4d.ID_USERDATA, id] = bc[c4d.DESC_DEFAULT]
                                    except:
                                        pass
                                            
                        def get_descid_bc(obj, dict) :
                            for descid, bc in obj.GetUserDataContainer() :
                                dict[descid[-1].id] = [descid, bc]
                                            
                                    
                        def main() :
                            #Get the object attached ot the tag
                            obj = op.GetObject()
                            
                            #Tell to python we use the global variable
                            global dict_descid_bc
                            
                            #Only update our dict if not build yet.
                            if not dict_descid_bc:
                                dict_descid_bc = dict()
                                get_descid_bc(obj, dict_descid_bc)
                            
                            #list who store all our data
                            #Reset_id, List_of_id_to_reset, list_of_descid_bc
                            datas = list()
                          
                            #Data exemple for G_Vegas
                            tupe_G_vegas = (486, 15, 17, 4, 44, 42, 27, 28, 512, 36, 29, 393, 38, 39, 40, 19, 389)
                            datas.append([486, tupe_G_vegas ])
                          
                            #Loop for each data then reset them
                            for data in datas:
                                reset(obj, data[0], data[1])
                                
                            #Trigger c4d update
                            c4d.EventAdd()
                          
                          
                        if __name__ == '__main__':
                            main()
                        

                        Tested and working fine in your exemple file.

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 04/06/2017 at 04:37, xxxxxxxx wrote:

                          Yes! This works! I have a question, though. The code below will reset everything within the group without hardcoding individual userdatas. I would like to avoid that as there are so many. Can this be done?

                          for id, bc in obj.GetUserDataContainer() :    
                                      if bc[c4d.DESC_PARENTGROUP][-1].id == 284: # G_Vegas Group
                                          try:
                                              obj[id] = bc[c4d.DESC_DEFAULT]
                                          except TypeError:
                                              pass
                          
                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 04/06/2017 at 04:42, xxxxxxxx wrote:

                            There are 16 user data variables for each of 10 presets and there are 10 sets of presets so I am looking at hardcoding 1600 userdatas. I would like to avoid that if possible and just use the Group user data id so that everything within the group is reset. Also, this way if I add to the group, I don't have to worry about the code missing that parameter because I didn't reference its specific ID.

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 04/06/2017 at 08:52, xxxxxxxx wrote:

                              Originally posted by xxxxxxxx

                              I never said that it was the proper solution to use Niklas.
                              I merely answered his question on "if there was a way to target a specific UD item without using a loop".
                              I never told him to use it. Nor did I tell him it was a better solution than yours.

                              -ScottA

                              You posted your answer without any information on potential
                              issues or limitations, thus I must assume that you either do not
                              know them or forgot to include them in your answer.

                              Either way, I feel obliged to point out that your answer only
                              works in a special case, namely when you create the userdata
                              sequentially and do not modify it afterwards.

                              If you answer a question without the intend of someone using
                              the information from your answer, why answer it at all.

                              -Niklas

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 04/06/2017 at 12:00, xxxxxxxx wrote:

                                Who the hell do you think you are Niklas?
                                And where do you get off talking to me in such a manner?
                                He asked a question. I even quoted it for clarity. Then I gave him the answer to that question.
                                He asked a specific question. And I gave him a specific answer. That's SOP.
                                It's not your place to give your almighty approval on how to answer someone's question.

                                I've managed hundreds of people and several business for over three decades. And some 20 something yr old snot nosed punk on the internet with the ego the size of 747 who thinks he's God's gift to coding is going to tell me how to properly reply to a question?
                                Oh hell no.
                                You weren't even an idea when I was managing people for a living.
                                Seriously. Who the hell do you think you are talking to me in that way?
                                That was way out of line.

                                -ScottA

                                1 Reply Last reply Reply Quote 0
                                • H
                                  Helper
                                  last edited by

                                  On 04/06/2017 at 16:36, xxxxxxxx wrote:

                                  Originally posted by xxxxxxxx

                                  Who the hell do you think you are Niklas?
                                  And where do you get off talking to me in such a manner?
                                  He asked a question. I even quoted it for clarity. Then I gave him the answer to that question.
                                  He asked a specific question. And I gave him a specific answer. That's SOP.
                                  It's not your place to give your almighty approval on how to answer someone's question.

                                  I've managed hundreds of people and several business for over three decades. And some 20 something yr old snot nosed punk on the internet with the ego the size of 747 who thinks he's God's gift to coding is going to tell me how to properly reply to a question?
                                  Oh hell no.
                                  You weren't even an idea when I was managing people for a living.
                                  Seriously. Who the hell do you think you are talking to me in that way?
                                  That was way out of line.

                                  -ScottA

                                  Dear Scott, I am sorry if you feel personally assaulted. My intentions are solely directed at improving
                                  accuracy of information in this thread. I do not want to further derail this thread, so if you feel like
                                  continuing this discussion, I invite you to contact me via PM.

                                  Regards,
                                  -Niklas

                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    On 04/06/2017 at 17:46, xxxxxxxx wrote:

                                    Is there a way instead of using the tuple to just use the group user ID and some code that refers to what's under it instead of hardcoding what's under it? That would solve the problem.

                                    1 Reply Last reply Reply Quote 0
                                    • H
                                      Helper
                                      last edited by

                                      On 04/06/2017 at 19:10, xxxxxxxx wrote:

                                      @Niklas.
                                      Thank you for apologizing.
                                      We're cool. But wow man. Take it easy on that whole "correction" stuff.
                                      I'm not exactly a rookie at this. I've been here longer than you and the last thing I need is posting lessons from you. So cut the crap dude. Or I'll swim over there and kick you're little butt. 😉
                                      Lets just shake hands and put it behind us.

                                      -ScottA

                                      1 Reply Last reply Reply Quote 0
                                      • H
                                        Helper
                                        last edited by

                                        On 05/06/2017 at 02:40, xxxxxxxx wrote:

                                        This code resets all the UD under it.

                                        for id, bc in obj.GetUserDataContainer() :    
                                                    if bc[c4d.DESC_PARENTGROUP][-1].id == 284: # G_Vegas Group
                                                        try:
                                                            obj[id] = bc[c4d.DESC_DEFAULT]
                                                        except TypeError:
                                                            pass
                                        

                                        Can this somehow be incorporated into this?

                                        import c4d
                                          
                                        #dict who gonna store all our bc and descid. Like that we iterate only 1 time.
                                        #dict["user_data_id"] = [descid, bc]
                                        #I use global vairable liek that we only have to do build it one time.
                                        #take care if you add/remove ud you need to update it, look the main function
                                        global dict_descid_bc
                                        dict_descid_bc = None
                                          
                                        def reset(obj, id_reset, list_id) :
                                            global dict_descid_bc
                                            ud_bc = obj.GetUserDataContainer()
                                            
                                            #Only if reset is True
                                            if obj[c4d.ID_USERDATA, id_reset]:
                                                obj[c4d.ID_USERDATA, id_reset] = False
                                                #We list all our id who are into our list_of_id_to_reset
                                                for id in list_id:
                                                    if id == id_reset:
                                                        continue
                                                    
                                                    descid = dict_descid_bc[id][0]
                                                    bc = dict_descid_bc[id][1]
                                                    try:
                                                        obj[c4d.ID_USERDATA, id] = bc[c4d.DESC_DEFAULT]
                                                    except:
                                                        pass
                                                            
                                        def get_descid_bc(obj, dict) :
                                            for descid, bc in obj.GetUserDataContainer() :
                                                dict[descid[-1].id] = [descid, bc]
                                                            
                                                    
                                        def main() :
                                            #Get the object attached ot the tag
                                            obj = op.GetObject()
                                            
                                            #Tell to python we use the global variable
                                            global dict_descid_bc
                                            
                                            #Only update our dict if not built yet.
                                            if not dict_descid_bc:
                                                dict_descid_bc = dict()
                                                get_descid_bc(obj, dict_descid_bc)
                                            
                                            #list who store all our data
                                            #Reset_id, List_of_id_to_reset, list_of_descid_bc
                                            datas = list()
                                          
                                            #Data exemple for G_Vegas
                                            tupe_G_vegas = (486, 15, 17, 4, 44, 42, 27, 28, 512, 36, 29, 393, 38, 39, 40, 19, 389)
                                            datas.append([486, tupe_G_vegas ])
                                          
                                            #Loop for each data then reset them
                                            for data in datas:
                                                reset(obj, data[0], data[1])
                                                
                                            #Trigger c4d update
                                            c4d.EventAdd()
                                          
                                          
                                        if __name__ == '__main__':
                                            main()
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • H
                                          Helper
                                          last edited by

                                          On 06/06/2017 at 01:41, xxxxxxxx wrote:

                                          Since I seriously doubt you try to understand code, I don't comment my code. But fel free to ask 😉

                                          import c4d
                                            
                                          def reset(obj, group_id) :
                                              for descid, bc in obj.GetUserDataContainer() :
                                                  if bc[c4d.DESC_PARENTGROUP][-1].id in group_id:
                                                      try:
                                                          obj[descid] = bc[c4d.DESC_DEFAULT]
                                                      except:
                                                          pass
                                            
                                          def get_group_to_get(obj, datas) :
                                              buffer = list()
                                              for i in xrange(len(datas)) :
                                                  if obj[c4d.ID_USERDATA, datas[i][0]]:
                                                      obj[c4d.ID_USERDATA, datas[i][0]] = False
                                                      buffer.append(datas[i][1])
                                            
                                              return buffer
                                            
                                            
                                          def main() :
                                              # Get the object attached ot the tag
                                              obj = op.GetObject()
                                            
                                              #list of list[enable_id, group_id]
                                              datas = [[486, 284],
                                                       ]
                                            
                                              group_to_check = get_group_to_get(obj, datas)
                                              if not group_to_check:
                                                  return
                                            
                                              #Reset data
                                              reset(obj, group_to_check)
                                            
                                            
                                            
                                              # Trigger c4d update
                                              c4d.EventAdd()
                                            
                                            
                                          if __name__ == '__main__':
                                              main()
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • H
                                            Helper
                                            last edited by

                                            On 06/06/2017 at 02:02, xxxxxxxx wrote:

                                            I would still suggest to retrieve the UserData once and store it globally, to avoid calling
                                            GetUserDataContainer() multiple times. Converting it to a dictionary reduces the time
                                            searching for an entry with a specific ID immensely.

                                            import c4d
                                              
                                            # A dictionary that stores the object's UserData where the keys
                                            # are the UserData ID's and the values are the (DescID, BaseContainer)
                                            # pairs returned by GetUserDataContainer()
                                            ud = None
                                              
                                            def main() :
                                                obj = op.GetObject()
                                                
                                                # We could also do this once really (if ud is None: ...) but it
                                                # would make development harder since the tag would need to be
                                                # "refreshed" everytime you change the userdata. It's still a LOT
                                                # better than using GetUserDataContainer() multiple times and it
                                                # also enhances search times for entries with specific IDs.
                                                global ud
                                                ud = dict((dd[-1].id, (dd, bc)) for dd, bc in obj.GetUserDataContainer())
                                              
                                                # ...
                                              
                                            def reset(obj, group_id) :
                                                for dd, bc in ud.itervalues() :
                                                    if bc[c4d.DESC_PARENTGROUP][-1].id in group_id:
                                                        try:
                                                            obj[dd] = bc[c4d.DESC_DEFAULT]
                                                        except TypeError:
                                                            pass
                                            

                                            To look up an entry with a spefic ID, you'd just use the ud Dictionary.

                                            def main() :
                                                # ...
                                              
                                                desc_id, bc = ud[4]  # Get's DescID and item description of userdata with ID 4
                                            

                                            On a side note, you will loose the order of the items returned by GetUserDataContainer(). But it
                                            appears that you do not need it anyway.

                                            -Niklas

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post