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

    Best practice getting all objects in a certain Null

    Cinema 4D SDK
    3
    12
    1.8k
    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.
    • ManuelM
      Manuel
      last edited by Manuel

      hi,

      there is no function to do it, you must retrieve the next object yourself in the hierarchy. Something like this exemple but you would need to test if the current object is not your null object, otherwise you would go outside the hierarchy.

      Cheers,
      Manuel

      MAXON SDK Specialist

      MAXON Registered Developer

      1 Reply Last reply Reply Quote 0
      • M
        mogh
        last edited by

        Thanks @m_magalhaes

        yes I can get the name (of the first Object) and check that and getup till I reach it, still I am worried that I can not say for certain what "objecst" c4d.documents.MergeDocument() gave me ...

        "certain Null" is not defined other than it is inserted at the top from C4D ... so i guess I have to get the Null by listing all root nulls bevore and after the import.

        Sorry I was a bit unclear and its 2 question in one as I am still "brainstoring"

        kind regards
        mogh

        1 Reply Last reply Reply Quote 0
        • ManuelM
          Manuel
          last edited by Manuel

          hi,

          In that case, i would open the document in a memory file structure, run my cleaning functions, save it on the memory file structure and merge the saved document.

          if you really need to merge first, i would retrieve the first object of the document before merging the documents and check if i hit it.

          Cheers,
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • M
            mogh
            last edited by

            As I am already running into problems with my current cleanup which proceses the tree more than once -> I think i have to open the import into "memory file structure" but I am not really clear what you mean from a functional standpoint.

            There are several interesting builtin function.

            c4d.documents.MergeDocument(doc, name, loadflags, thread) # <- used ATM
            
            c4d.documents.LoadFile(name)
            c4d.documents.LoadDocument(name, loadflags, thread=None)
            
            c4d.documents.IsolateObjects(doc, t_objects) # whats the 
            
            

            Whats the difference between MergeDocument and LoadDocument with SCENEFILTER_MERGESCENE flags ?
            Why has MergeDocument a SCENEFILTER_MERGESCENE Flag ?

            are my asumption right:

            1. create a new DOC e.g. tempdoc
            2. LoadFile/ LoadDocument / MergeDocument into that - which one ?
            3. copy objects or merge doc again ?

            thanks in advance
            mogh

            ferdinandF 1 Reply Last reply Reply Quote 0
            • M
              mogh
              last edited by

              my WIP prototype, but the generated cubes are not "present" in the merged document yet.

              import c4d
              from c4d import gui
              #from c4d.documents import GetActiveDocument
              
              
              def create_obj(doc):
                  obj = c4d.BaseObject(c4d.Ocube)
                  obj.SetName("importedcube")
                  doc.InsertObject(obj)
                  c4d.EventAdd()
              
              def main():
                      doc = c4d.documents.GetActiveDocument()
                      print("Active Doc: ", doc.GetDocumentName())
                      
                      dirpath = r"c:\\"
                      doctemp = None
                     
                      if doctemp==None:
                          doctemp = c4d.documents.BaseDocument()
                          doctemp.SetDocumentName("temp_import.c4d")
                          doctemp.SetDocumentPath(dirpath)
                          
                          c4d.documents.InsertBaseDocument(doctemp) # calls set active allready
                          #c4d.documents.SetActiveDocument(doctemp)
              
                      create_obj(doctemp)
                      create_obj(doctemp)
                      
                      """
                      obj = doc.GetActiveObject()
                      if obj is None:
                          print("No active object")
                          c4d.documents.KillDocument(doctemp)
                          return        
                      isolateDoc = c4d.documents.IsolateObjects(doctemp, [obj])
                      """
              
                      mfs = c4d.storage.MemoryFileStruct()
                      mfs.SetMemoryWriteMode()
                      c4d.documents.SaveDocument(doctemp, mfs, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT)
                      data = mfs.GetData()
                      mfs.SetMemoryReadMode(data[0], data[1] )
              
                      
                      if c4d.documents.MergeDocument(doc, mfs, loadflags=c4d.SCENEFILTER_MERGESCENE, thread=None ): #  c4d.SCENEFILTER_MERGESCENE | c4d.SCENEFILTER_NOUNDO, 
                          print("merged",  mfs)
              
                      
                      #doctemp.Flush()
                      c4d.documents.KillDocument(doctemp)
                      
                      #c4d.documents.SetActiveDocument(doc)
              
              
              
              # Execute main()
              if __name__=='__main__':
                  c4d.CallCommand(13957) # clear concole
                  main()
              
              1 Reply Last reply Reply Quote 0
              • ferdinandF
                ferdinand @mogh
                last edited by

                Hello @mogh,

                @m_magalhaes is on a brief vacation, I will quickly jump in here.

                Whats the difference between MergeDocument and LoadDocument with SCENEFILTER_MERGESCENE flags ? Why has MergeDocument a SCENEFILTER_MERGESCENE Flag?

                As stated in the docs, SCENEFILTER_MERGESCENE, primarily meant for plugins. Meant are here importer plugins, the FBX importer plugin will for example make some different decisions when the flag signals that the document to be loaded is meant to be merged with an existing scene. The key flags in SCENEFILTER are OBJECTS and MATERIALS when one wants to load in only that aspect of a document. You can also pass in additionally MERGESCENE, e.g., in Python c4d.SCENEFILTER_MERGESCENE | c4d.SCENEFILTER_OBJECTS, but it does not make a difference in most cases. The SCENEFILTER enum is also used in other contexts than MergeDocument().

                LoadFile/ LoadDocument / MergeDocument into that - which one ?

                That does depend on what you want to do. In principle I would favour them in the order you mentioned them. When possible, I would use LoadFile(), as this will give you all the file handling that Cinema 4D has, i.e., you can also open a bitmap in this way. It also perseveres the full scene state of a Cinema 4D file. But it will not give directly a BaseDocument (one can of course grab it manually via c4d.documents.GetFirstDocument() and then seraching for it) and will cause the file to be shown in Cinema 4D. When one requires a BaseDocument and does not want the file to be loaded by Cinema 4D, one should use LoadDocument(). Finally, when one must merge two files or wants to load only parts of a file, for example its materials, one should use MergeDocument(), but it will not preserve the active camera of the loaded in file, even when one indicates via the flags that everything should be loaded.

                Cheers,
                Ferdinand

                MAXON SDK Specialist
                developers.maxon.net

                1 Reply Last reply Reply Quote 1
                • M
                  mogh
                  last edited by

                  @ferdinand Thanks, you pointed me to my error:

                  The above code needs these scene flags to work properly ....
                  as the MergeDocument() merges only with certain flags ... (c4d.SCENEFILTER_MERGESCENE will not work this is a gotcha ...)

                  c4d.documents.MergeDocument(doc, mfs, loadflags=c4d.SCENEFILTER_OBJECTS , thread=None ):

                  So to update my blueprint:

                  1. LoadDocument() to tempdoc (need to test this ...)
                  2. Cleanup
                  3. save tempdoc to MemoryFileStruct()
                  4. merge "open/active" c4d File with MemoryFileStruct() (similar to prototype above)

                  @SDKTeam
                  I will update and set to solved when I do get a prototype working. please be patient.

                  thanks
                  mogh

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

                    Hey mogh,

                    I also had a look at your code, and I cleaned up some things. This works for me as I would expect it to work.

                    Cheers,
                    Ferdinand

                    import c4d
                    
                    def create_obj(doc):
                        """
                        """
                        obj = c4d.BaseObject(c4d.Ocube)
                        obj.SetName("importedcube")
                        doc.InsertObject(obj)
                    
                    def main():
                        """
                        """
                        # I removed a lot of clutter here.
                        temp = c4d.documents.BaseDocument()
                        create_obj(temp)
                    
                        mfs = c4d.storage.MemoryFileStruct()
                        mfs.SetMemoryWriteMode()
                        c4d.documents.SaveDocument(temp, mfs, 
                            c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT)
                        data = mfs.GetData()
                        mfs.SetMemoryReadMode(data[0], data[1])
                    
                        # In this case you want to load in the objects and materials I assume.
                        flags = c4d.SCENEFILTER_MERGESCENE | c4.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS
                        if c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
                            print()
                    
                        # You were missing an event add.
                        c4d.EventAdd()
                    
                    # Execute main()
                    if __name__ == '__main__':
                        c4d.CallCommand(13957)  # clear concole
                        main()
                    

                    MAXON SDK Specialist
                    developers.maxon.net

                    1 Reply Last reply Reply Quote 1
                    • M
                      mogh
                      last edited by mogh

                      How do I catch / prevent a "ReferenceError: the object 'c4d.documents.BaseDocument' is not alive"
                      when the user has an unsaved / unclicked / unactive doc as master ?

                      my problem ist the

                      if not c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
                      

                      it fails while your

                      if c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
                      

                      is error free

                      thanks

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

                        Hello @mogh,

                        @mogh said in Best practice getting all objects in a certain Null:

                        I will update and set to solved when I do get a prototype working. please be patient.

                        There is no need to feel rushed. We close threads after 14 days of inactivity, but when users say they want to keep them open when we request a closing, we keep them open much longer. It is only that we will ask every 14 days.

                        my problem ist the

                        if not c4d.documents.MergeDocument(doc, mfs, loadflags=flags):

                        it fails while your

                        if c4d.documents.MergeDocument(doc, mfs, loadflags=flags):

                        The negation operator is certainly not the culprit, at least I could not imagine how. A Python object that is not alive anymore, means that the Python bindings and the C++ backend have gone out of sync. Or in other words, there is still a reference to an object in Python but the data it is wrapping living in the C++ backend has been deallocated. You can test an object for being still alive with c4d.C4DAtom.IsAlive().

                        However, when I looked at your script, I first ran into similar problems. The culprit must have been the document inside the MFS, because when I tested doc it was still alive, as it was still open in the editor (c4d.documents.BaseDocument is also a node, i.e., derived from C4DAtom). But then the problem vanished, and I could not reproduce it anymore. I do not think that your code is or my code was the issue. I would recommend restarting Cinema 4D and see if the problem then does vanish. Otherwise we have to see if either the MFS or MergeDocument Python wrappers produces dangling pointers in some cases.

                        FYI: I just ran the code below, i.e., with a not, and it runs fine for me.

                        Cheers,
                        Ferdinand

                        import c4d
                        
                        def create_obj(doc):
                            """
                            """
                            obj = c4d.BaseObject(c4d.Ocube)
                            obj.SetName("importedcube")
                            doc.InsertObject(obj)
                        
                        def main():
                            """
                            """
                            # I removed a lot of clutter here.
                            temp = c4d.documents.BaseDocument()
                            create_obj(temp)
                        
                            mfs = c4d.storage.MemoryFileStruct()
                            mfs.SetMemoryWriteMode()
                            c4d.documents.SaveDocument(temp, mfs, 
                                c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT)
                            data = mfs.GetData()
                            mfs.SetMemoryReadMode(data[0], data[1])
                        
                            # In this case you want to load in the objects and materials I assume.
                            flags = c4d.SCENEFILTER_MERGESCENE | c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS
                            if not c4d.documents.MergeDocument(doc, mfs, loadflags=flags):
                                print("Blah")
                        
                            # You were missing an event add.
                            c4d.EventAdd()
                        
                        # Execute main()
                        if __name__ == '__main__':
                            c4d.CallCommand(13957)  # clear concole
                            main()
                        

                        MAXON SDK Specialist
                        developers.maxon.net

                        1 Reply Last reply Reply Quote 0
                        • M
                          mogh
                          last edited by

                          Found the problem I tried to Kill a document which was not alive, don't know if this is necessary with a merge.

                              if c4d.C4DAtom.IsAlive(temp):
                                  c4d.documents.KillDocument(temp)
                          

                          And another gotcha c4d.documents.SetActiveDocument(temp) seems to be mandatory if you want to use CallCommand() -> and do not to forget to set the doc back to active after your routine.

                          Thank you

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