Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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
    • Recent
    • Tags
    • Users
    • Register
    • Login

    File import and doc merge -> InsertAfter or c4d.PREF_INTERFACE_I_BOTTOM

    Scheduled Pinned Locked Moved Cinema 4D SDK
    python2026
    4 Posts 3 Posters 39 Views 3 Watching
    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.
    • M Offline
      mogh
      last edited by

      Dear Team,
      I am trying to import files and place them in the object tree in the right order,

      i tried to set the preferences with c4d.PREF_INTERFACE_I_BOTTOM before import but it did not change my order.

              interface_preferences = c4d.GetWorldContainer()
              previous_insert_at = interface_preferences.GetInt32(c4d.PREF_INTERFACE_INSERTAT)
              interface_preferences.SetInt32(c4d.PREF_INTERFACE_INSERTAT, c4d.PREF_INTERFACE_I_BOTTOM, )
      

      Is there a convenient way or do i need to move the "node" manually to the bottom on each import ...
      or more universal for me is there a way to sort root nodes in the Object manager tree ? (only found an old coffee thread ... )
      thanks in advance ...
      mogh

      1 Reply Last reply Reply Quote 0
      • AnlvA Offline
        Anlv
        last edited by Anlv

        import c4d
        
        doc: c4d.documents.BaseDocument  # The currently active document.
        op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
        
        def main() -> None:
        
            obj = c4d.BaseObject(c4d.Ocube)
        
            # Insert after the last root object.
            roots = doc.GetObjects()
            doc.InsertObject(obj, pred=roots[-1] if roots else None)
        
            c4d.EventAdd()
            
        if __name__ == '__main__':
            main()
        

        Hope this helps.
        Here is another example that can directly execute the import

        import c4d
        
        def main():
            doc = c4d.documents.GetActiveDocument()
            path = c4d.storage.LoadDialog(
                c4d.FILESELECTTYPE_SCENES,
                "Import Scene"
            )
            if not path:
                return
        
            roots = doc.GetObjects()
            anchor = roots[-1] if roots else None
            old_guids = {obj.GetGUID() for obj in roots}
        
            flags = (
                c4d.SCENEFILTER_OBJECTS |
                c4d.SCENEFILTER_MATERIALS |
                c4d.SCENEFILTER_MERGESCENE |
                c4d.SCENEFILTER_DIALOGSALLOWED
            )
        
            c4d.StopAllThreads()
            doc.StartUndo()
        
            try:
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, doc)
        
                if not c4d.documents.MergeDocument(doc, path, flags, None):
                    c4d.gui.MessageDialog("Import failed.")
                    return
        
                # Find the newly imported root objects.
                imported = [
                    obj for obj in doc.GetObjects()
                    if obj.GetGUID() not in old_guids
                ]
        
                # Move them below the previous last root object.
                if anchor:
                    for obj in imported:
                        matrix = obj.GetMg()
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
                        obj.Remove()
                        obj.InsertAfter(anchor)
                        obj.SetMg(matrix)
                        anchor = obj
            finally:
                doc.EndUndo()
                c4d.EventAdd()
        
        if __name__ == "__main__":
            main()
        

        Cheers,
        Anlv

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

          Hey @mogh,

          let me clarify things first a bit.

          Reproduce:

          1. You have a scene A in an alien scene format such as FBX or OBJ.
          2. You have an existing native Cinema 4D scene B.
          3. You are trying to merge A into B.

          Result:
          The objects of A appear before the objects of B in the scene hierarchy of the merged scene. Even when you change the insertion order in Preferences > Interface.

          First of all, it is not very surprising that "insert at" does not work (and "paste at" does neither), because these are for individual objects within a scene, not for merging entire scenes. What you are effectively missing is a scene merge order option and this does not really have something to do with importers. This would be addressed best by a feature request in our Support Center.

          With a pinch of Python, you can solve this yourself as demonstrated by @Anlv (thanks!). Using BaseList2D.GetGUID as @Anlv did is okay, but the more native solution would be hash(obj), i.e., C4DAtom.__hash__. Scene elements are for quite a while now natively hashable, so you can for example do this:

          roots: set[int] = { hash(obj) for obj in doc.GetObjects() }
          new_roots: set[int] = roots.intersection({ hash(obj) for obj in new_doc.GetObjects() })
          

          And it will give you the set of all root level hashes (GeMarker IDs). I think also the transform copying @Anlv does at the end of the script should not be necessary, because these are root level objects, and therefore removing and re-adding them will not affect their transforms (as they have no parents to which their transform would be relative to). But I have not run @Anlv's full script myself, so it could be that I am overlooking something.

          Cheers,
          Ferdinand

          MAXON SDK Specialist
          developers.maxon.net

          AnlvA 1 Reply Last reply Reply Quote 1
          • AnlvA Offline
            Anlv @ferdinand
            last edited by

            @ferdinand Thanks for pointing that out. Indeed, matrix = obj.GetMg() and obj.SetMg(matrix) are not necessary; this is leftover code from when it was previously used to insert into the child or sibling level of the selected object.

            Cheers,
            Anlv

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