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.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...