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
    • Register
    • Register
    • 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.
    • M
      mogh
      last edited by

      Dear Developpers,

      I have a script importing files, on which I perform serverall cleanup methods.
      Now i want to restrict the methods only on the freshly importet data.
      Meaning only getting the objects of a certain null object.
      How should i tacle this?

      break the getnext() loop if there is no getup()
      (because imports are always on top ? ) probably not save.

      Is there a more robuts idea to get all objects of a certain Null ?

      kind regards.
      mogh

      1 Reply Last reply Reply Quote 0
      • 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