• Categories
    • Overview
    • News & Information
    • Cinema 4D SDK Support
    • Cineware SDK Support
    • ZBrush 4D SDK Support
    • Bugs
    • General Talk
  • Unread
  • Recent
  • Tags
  • Users
  • Register
  • Login
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
  • Login

Best practice getting all objects in a certain Null

Cinema 4D SDK
3
12
1.3k
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
    Manuel
    last edited by Manuel Jan 19, 2022, 5:46 PM Jan 19, 2022, 5:45 PM

    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 Jan 20, 2022, 5:37 PM

      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
      • M
        Manuel
        last edited by Manuel Jan 21, 2022, 2:13 PM Jan 21, 2022, 2:08 PM

        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 Jan 31, 2022, 12:02 PM

          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

          F 1 Reply Last reply Feb 2, 2022, 1:42 PM Reply Quote 0
          • M
            mogh
            last edited by Feb 2, 2022, 11:57 AM

            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
            • F
              ferdinand @mogh
              last edited by Feb 2, 2022, 1:42 PM

              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 Feb 2, 2022, 2:23 PM

                @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

                F 1 Reply Last reply Feb 2, 2022, 5:17 PM Reply Quote 0
                • F
                  ferdinand
                  last edited by Feb 2, 2022, 2:59 PM

                  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 Feb 2, 2022, 3:25 PM Feb 2, 2022, 3:19 PM

                    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
                    • F
                      ferdinand @mogh
                      last edited by ferdinand Feb 2, 2022, 5:19 PM Feb 2, 2022, 5:17 PM

                      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 Feb 2, 2022, 10:05 PM

                        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