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

    Copy children to selection with GetClone()

    Cinema 4D SDK
    python 2024
    2
    3
    606
    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.
    • John_DoJ
      John_Do
      last edited by

      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 !

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @John_Do
        last edited by ferdinand

        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 calls node.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

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • John_DoJ
          John_Do
          last edited by

          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()
          
          
          1 Reply Last reply Reply Quote 1
          • First post
            Last post