Copy children to selection with GetClone()
-
Hi all,
I'm writing a script to copy the children objects of an "active" object to other selected objects using the GetClone() function, but I can't get it to work as intended, I feel I'm missing something obvious. The intent is to copy deformers from the active object to all others (but I don't want to limit the function to deformers).
import c4d doc = c4d.documents.GetActiveDocument() def main(): doc.StartUndo() objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER) if len(objs) >= 2: # Get the last selected object active = objs.pop(-1) # --------------------------------- Method A --------------------------------- # # Get the deformers deformers = [i.GetClone(c4d.COPYFLAGS_NO_BITS) for i in active.GetChildren()] # Copy deformer to selection if deformers: for o in objs: for d in deformers[::-1]: doc.InsertObject(d, parent=o) doc.AddUndo(c4d.UNDOTYPE_NEW, d) # --------------------------------- Method B --------------------------------- # # # Get the deformers # deformers = [i for i in active.GetChildren()] # Copy deformer to selection # if deformers: # for o in objs: # for d in deformers[::-1]: # doc.InsertObject(d.GetClone(c4d.COPYFLAGS_NO_BITS), parent=o) # doc.AddUndo(c4d.UNDOTYPE_NEW, d) doc.EndUndo() c4d.EventAdd() if __name__ == '__main__': main()
The method A kinda works but do only one copy and stop without error. I didn't see anything meaningful after printing the lists content in various steps of the script, everything seems ok from my understanding.
The method B kinda works too and successfully copy deformers on all the selected objects but the undo is very buggy ( multiple steps rather than one as intended, delete deformers on the active object).Also the newly inserted objects open the hierarchies in the OM, is it because it's the default behavior of C4D when creating child objects ? Do I have to toggle BIT_OFOLD manually ?
Thanks !
-
Hey @John_Do,
Thank you for reaching out to us. We will answer on Monday in more detail as you have just missed our morning meeting where we assign topics. But when I look at your code, it seems like you are inserting your deformers multiple times.
if deformers: for o in objs: for d in deformers[::-1]: doc.InsertObject(d, parent=o) doc.AddUndo(c4d.UNDOTYPE_NEW, d)
Without having run your script, this reads to me like you are inserting each element of
deformers
len(objs)
times. A node can only be inserted once into a scene or really bad things are going to happen. Python has a fail-safe for this as it callsnode.Remove
in the implementation of most insertion methods. When you pair this with your undo, wonky results are not surprising I would say. When you want to insert your deformers multiple times, you must clone them for each insertion.Cheers,
Ferdinand -
Hi @ferdinand, thanks for the feedback, I've got it working with your suggestion. The method B was correct but the undo part was wrong ( the undo step was applied on the original objects instead of the new ones, thus leading to a mess when performing an undo). I also added the bit part to keep new objects folded in the OM. Here is the code :
# CopyDeformers import c4d doc = c4d.documents.GetActiveDocument() def main(): doc.StartUndo() objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER) if len(objs) >= 2: # Get the last selected object active = objs.pop(-1) # Get the deformers deformers = [i for i in active.GetChildren()] # Copy deformers to selection if deformers: for o in objs: for d in deformers[::-1]: dcopy = d.GetClone(c4d.COPYFLAGS_NO_BITS) doc.InsertObject(dcopy, parent=o) doc.AddUndo(c4d.UNDOTYPE_NEW, dcopy) o.SetBit(c4d.BIT_MFOLD) doc.EndUndo() c4d.EventAdd() if __name__ == '__main__': main()