Jump to content

Easier iteration


dancouto

Recommended Posts

Hi. I have some Python code that resets user data in a group. What I have written looks to be very cumbersome and it is very slow when I have a lot of resets. Here is what I have:

 
import c4d
 
        
def main():
    
    ID_G_Vegas_RESET = 486
    ID_G_Motel_RESET = 485
    ID_G_Spitn_Kitten_RESET = 489
    ID_G_Vacancy_RESET = 490
    ID_G_Open_RESET = 491
    ID_G_Sports_Bar_RESET = 492
    ID_G_Heinek_RESET = 508
    ID_G_Claude_RESET = 509
    ID_G_Argon_RESET = 510
    ID_G_Xenon_RESET = 511
 
# RESET G ------------------------------------------------------------    
    
    #RESET G_Vegas
    if obj[c4d.ID_USERDATA, ID_G_Vegas_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Vegas_RESET] = False
 
        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
        
          
    #RESET G_Motel
    if obj[c4d.ID_USERDATA, ID_G_Motel_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Motel_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 285: # G_Motel Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_The Spit'n Kitten'
    if obj[c4d.ID_USERDATA, ID_G_Spitn_Kitten_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Spitn_Kitten_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 287: # G_The Spit'n Kitten Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Vacancy
    if obj[c4d.ID_USERDATA, ID_G_Vacancy_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Vacancy_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 289: # G_Vacancy Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Open
    if obj[c4d.ID_USERDATA, ID_G_Open_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Open_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 291: # G_Open Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Sports Bar
    if obj[c4d.ID_USERDATA, ID_G_Sports_Bar_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Sports_Bar_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 293: # G_Sports Bar
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Heinek
    if obj[c4d.ID_USERDATA, ID_G_Heinek_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Heinek_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 295: # G_Vegas Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Claude
    if obj[c4d.ID_USERDATA, ID_G_Claude_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Claude_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 297: # G_Claude Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
 
 
    #RESET G_Argon
    if obj[c4d.ID_USERDATA, ID_G_Argon_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Argon_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 299: # G_Argon Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
                    
    #RESET G_Xenon
    if obj[c4d.ID_USERDATA, ID_G_Xenon_RESET]:
        obj[c4d.ID_USERDATA, ID_G_Xenon_RESET] = False
 
        for id, bc in obj.GetUserDataContainer():    
            if bc[c4d.DESC_PARENTGROUP][-1].id == 301: # G_Xenon Group
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
 
c4d.EventAdd()
 
 
I know there is a better way to do this. Can anyone offer a suggestion? Thanks.
Link to post

Could you provide a scene exemple? Anyway here is a not optimized but cleaned for doing what you want.

Provide me scene and I will optimize it.

import c4d

def reset(id_reset, id_parent):
    if obj[c4d.ID_USERDATA, id_reset]:
        obj[c4d.ID_USERDATA, id_reset] = False

        for id, bc in obj.GetUserDataContainer():
            if bc[c4d.DESC_PARENTGROUP][-1].id == id_parent:
                try:
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                finally:
                    break #Stop loop since we got our parent


def main():
    datas = list()

    datas.append([486, 284])
    datas.append([485, 285])
    datas.append([489, 287])
    datas.append([490, 289])
    datas.append([491, 291])
    datas.append([492, 293])
    datas.append([508, 295])
    datas.append([509, 297])
    datas.append([510, 299])
    datas.append([511, 301])

    doc.StartUndo()
    for data in datas:
        reset(data[0], data[1])
    doc.EndUndo()
    c4d.EventAdd()


if __name__ == '__main__':
    main()

 

EDIT: here is one using thread, will probably crash your c4d so it's why I ask for a scene file ;)

import c4d

class MyThread(c4d.threading.C4DThread):
    id_reset = 0
    id_parent = 0
    obj = None

    def Main(self):
        self.obj[c4d.ID_USERDATA, self.id_reset] = False

        for id, bc in self.obj.GetUserDataContainer():
            if bc[c4d.DESC_PARENTGROUP][-1].id == self.id_parent:
                try:
                    self.obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                finally:
                    break  # Stop loop since we got our parent

def main():
    datas = list()

    datas.append([486, 284])
    datas.append([485, 285])
    datas.append([489, 287])
    datas.append([490, 289])
    datas.append([491, 291])
    datas.append([492, 293])
    datas.append([508, 295])
    datas.append([509, 297])
    datas.append([510, 299])
    datas.append([511, 301])

    list_thread = list()
    doc.StartUndo()
    for data in datas:
        if obj[c4d.ID_USERDATA, data[0]]:
            thread = MyThread()
            list_thread.append(thread)

            thread.id_reset = data[0]
            thread.id_parent = data[1]
            thread.obj = obj

            doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
            thread.Start()

    for thread in list_thread:
        thread.End()
    doc.EndUndo()
    c4d.EventAdd()


if __name__ == '__main__':
    main()

Moreover how do you get obj? it can be also that. Without your full code/exemple I can't do more

 

And I also encourage you to don't post on multiples forum since people may loose time to answerd you while another one already do ^^'.

Link to post

Got it regarding posting to multiple forums. Thanks for doing this. I tested both and can't get them to work. Here is a file where I have included a tag for each solution. Mine (DAN) works and is disabled. Thread is also disabled but does not work. Optimize is enabled and does not work. Can you take a look? 

reset test.c4d

Link to post

Ok didn't thinked you was into a tag. But it's ok ! :)

Anyway here is two methods. One automatic but which is not really optimized on object with a so huge amount of data.

import c4d

def reset(id_reset, id_parent, last_id):
  	#Since we are in a tag is way more clean to do obj = op.GetObject than to proccess a search in the whole document.
    obj = op.GetObject()
    
    #Only if reset is True
    if obj[c4d.ID_USERDATA, id_reset]:
        obj[c4d.ID_USERDATA, id_reset] = False

        #We list all our data
        for id, bc in obj.GetUserDataContainer():
          	#Check if the parent_group = id_parent if yes reset
            if bc[c4d.DESC_PARENTGROUP][-1].id == id_parent:
                try:
                    obj[id] = bc[c4d.DESC_DEFAULT]
                except TypeError:
                    pass
                    
            #Don't use elif we want the conditional statement before to have effect ! So if it's our last id we left the loop
            if id == last_id:
                break
            
            
def main():
	#list who store all our data
    #Reset_id, Group_id, Last_id_in_group
    datas = list()

	#Data exemple for G_Vegas
    datas.append([486, 284, 389])

	#Loop for each data then reset them
    for data in datas:
        reset(data[0], data[1])
    c4d.EventAdd()


if __name__ == '__main__':
    main()

 

Here is my second method way more optimized. Since you loop into all ud only 1 time. But for that you need to have a list of all userData under parent_id (but I have made a quick script for retrieve them ;) So basicly. Here is the code into the tag. I hope you understand it.

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
    list_G_vegas = [486, 15, 17, 4, 44, 42, 27, 28, 512, 36, 29, 393, 38, 39, 40, 19, 389]
    datas.append([486, list_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()

 

And here is the script I used for get the list_G_vegas. (just change the parent_id in the main function, open the console and you got it ;))

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 list_all_children
    

if __name__=='__main__':
    main()

But you only have to do it one time so I guess it's ok.

 

For future reader I will continue this discussion into plugincafee for the reason I exposed before.

http://www.plugincafe.com/forum/forum_posts.asp?TID=13629

Link to post

Archived

This topic is now archived and is closed to further replies.

ABOUT US

We are dedicated Cinema 4D Community of friendly and passionate artists, hobbyists and developers. Feel free to join us to share your knowledge, your art and anything that might help Community to grow. We are providing guidance, free plugins and files, feedback, sponsorships and various discounts for our Contributors and much more. :cowboypistol:

×
×
  • Create New...

Copyright C4D Cafe © 2021 Powered by Invision Community