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

    AddUndo() for MergeDocument() ?

    Cinema 4D SDK
    3
    16
    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.
    • A
      arsen
      last edited by

      Hi.
      Is it possible to add UNDO for documents.MergeDocument() operation?
      I tried this code but it does not work:

      doc.StartUndo()
      
      c4d.documents.MergeDocument(doc, obj_path,
                                  c4d.SCENEFILTER_OBJECTS |
                                  c4d.SCENEFILTER_MATERIALS |
                                  c4d.SCENEFILTER_MERGESCENE, None)
      
      c4d.StatusClear()
      c4d.EventAdd()
      
      obj = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)[0]
      while obj:
          obj = get_next_object(obj)
          doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
      
      doc.EndUndo()
      
      

      Thanks!

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

        hello,
        you can simply add the document with c4d.UNDOTYPE_CHANGE

        I did tried with a simple scene and it remove the object and the material. Let me know if it doesn't work for you.

            filePath = "C:\\myfile.c4d"
            doc.StartUndo()
            doc.AddUndo(c4d.UNDOTYPE_CHANGE, doc)
            c4d.documents.MergeDocument(doc, filePath,
                                    c4d.SCENEFILTER_OBJECTS |
                                    c4d.SCENEFILTER_MATERIALS |
                                    c4d.SCENEFILTER_MERGESCENE 
                                    , None)
            doc.EndUndo()
        

        Cheers
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        A 1 Reply Last reply Reply Quote 0
        • A
          arsen @Manuel
          last edited by

          @m_magalhaes
          No, this solution does not work for me. I am trying to add UNDO when importing an OBJ file.

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

            hi,

            Getting the example from our github repository and adding the undo part for the document.
            if it's not working, could you provide the scene ? Or maybe your code ?

            """
            Copyright: MAXON Computer GmbH
            Author: Joey Gaspe
            Description:
                - Imports Obj with custom settings.
            Class/method highlighted:
                - c4d.plugins.FindPlugin()
                - MSG_RETRIEVEPRIVATEDATA
                - c4d.documents.MergeDocument()
            Compatible:
                - Win / Mac
                - R13, R14, R15, R16, R17, R18, R19, R20, R21
            """
            import c4d
            
            
            def main():
                # Retrieves a path to load the imported file
                selectedFile = c4d.storage.LoadDialog(title="Load File for OBJ Import", type=c4d.FILESELECTTYPE_ANYTHING, force_suffix="obj")
                if not selectedFile:
                    return
            
                # Retrieves Obj import plugin, defined in R17 as FORMAT_OBJ2IMPORT and below R17 as FORMAT_OBJIMPORT
                objExportId = c4d.FORMAT_OBJIMPORT if c4d.GetC4DVersion() < 17000 else c4d.FORMAT_OBJ2IMPORT
                plug = c4d.plugins.FindPlugin(objExportId, c4d.PLUGINTYPE_SCENELOADER)
                if plug is None:
                    raise RuntimeError("Failed to retrieve the obj importer.")
            
                data = dict()
                # Sends MSG_RETRIEVEPRIVATEDATA to OBJ import plugin
                if not plug.Message(c4d.MSG_RETRIEVEPRIVATEDATA, data):
                    raise RuntimeError("Failed to retrieve private data.")
            
                # BaseList2D object stored in "imexporter" key hold the settings
                objImport = data.get("imexporter", None)
                if objImport is None:
                    raise RuntimeError("Failed to retrieve BaseContainer private data.")
            
                # Defines the settings
                objImport[c4d.OBJIMPORTOPTIONS_PHONG_ANGLE_DEFAULT] = 22.5
                objImport[c4d.OBJIMPORTOPTIONS_TEXTURECOORDINATES] = True
                objImport[c4d.OBJIMPORTOPTIONS_SPLITBY] = c4d.OBJIMPORTOPTIONS_SPLITBY_OBJECT
                objImport[c4d.OBJIMPORTOPTIONS_MATERIAL] = c4d.OBJIMPORTOPTIONS_MATERIAL_MTLFILE
                objImport[c4d.OBJIMPORTOPTIONS_POINTTRANSFORM_FLIPZ] = True
            
                # Finally imports without dialogs
                # Start undo for the document
                doc.StartUndo()
                # Add the document to the stack
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, doc)
                if not c4d.documents.MergeDocument(doc, selectedFile, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS, None):
                    raise RuntimeError("Failed to load the document.")
                # Finish the building of undo
                doc.EndUndo()
                # Pushes an update event to Cinema 4D
                c4d.EventAdd()
            
            
            if __name__ == '__main__':
                main()
            

            cheers,
            Manuel

            MAXON SDK Specialist

            MAXON Registered Developer

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

              Hi,

              @m_magalhaes solution should work just fine with obj files too. If you are getting no output you probably haven't escaped special characters in your file path properly. Alternatively you could also pass a raw string (then you don't have to escape special characters).

              file_path = r"C:\myfile.c4d
              

              The reason why your script is not working as expected is probably because you are only adding Undos for the selected objects. However only the last object that has been merged into the document will be selected after the merge operation.

              Cheers
              zipit

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 1
              • A
                arsen @Manuel
                last edited by

                @m_magalhaes

                here is my code

                import c4d
                from c4d import utils, documents, plugins
                
                import time
                from threading import Thread
                
                
                class WatchThread(Thread):
                    def __init__(self, name, doc):
                        Thread.__init__(self, name=name)
                        self.doc = doc
                
                    def run(self):
                        while True:
                            time.sleep(2.5)
                            obj_importer(self.doc, r'f:\01.obj')
                            print 'Loaded.',
                            break
                
                
                def obj_importer(doc, obj_path):
                    if obj_path is None:
                        return
                
                    plug = plugins.FindPlugin(1030177, c4d.PLUGINTYPE_SCENELOADER)
                    if plug is None:
                        return
                
                    op = {}
                    if plug.Message(c4d.MSG_RETRIEVEPRIVATEDATA, op):
                
                        if "imexporter" not in op:
                            return
                
                        obj_import = op["imexporter"]
                        if obj_import is None:
                            return
                
                        # Parameters
                        obj_import[c4d.OBJIMPORTOPTIONS_POINTTRANSFORM_SWAPXY] = False
                        obj_import[c4d.OBJIMPORTOPTIONS_POINTTRANSFORM_SWAPXZ] = False
                        obj_import[c4d.OBJIMPORTOPTIONS_POINTTRANSFORM_SWAPYZ] = True
                
                        doc.StartUndo()
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, doc)
                
                        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                
                        c4d.documents.MergeDocument(doc, obj_path,
                                                    c4d.SCENEFILTER_OBJECTS |
                                                    c4d.SCENEFILTER_MATERIALS |
                                                    c4d.SCENEFILTER_MERGESCENE, None)
                
                        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                
                        doc.EndUndo()
                
                        obj_import[c4d.OBJIMPORTOPTIONS_PRESETS] = 0
                
                    c4d.StatusClear()
                    c4d.EventAdd()
                
                
                if __name__ == '__main__':
                    doc = c4d.documents.GetActiveDocument()
                    wt = WatchThread('ht', doc)
                    wt.start()
                
                
                1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand
                  last edited by

                  Hi,

                  first of all: If you want to use threads, you should use c4d.threading.C4DThread and not Pythons builtin thread type or weird things might happen. Also note that threading comes with certain limitations:

                  For all threaded functions it is forbidden to:

                  • Add an event.
                    [...]
                  • Change the structure of objects attached to the document.
                    [...]
                  • Create undos.

                  I am also not quite sure what the purpose of your thread is, since you are loading into the active document. If you want to "load in the background" you will have to use a temporary document. But for loading just one file I do not see any performance benefits, since you have to merge that temporary document into the active document at the end.

                  Cheers
                  zipit

                  MAXON SDK Specialist
                  developers.maxon.net

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

                    hello,

                    well as @zipit said it's forbidden to change the structure of a document outside the main thread.
                    watch this page and the warning about threading

                    I did checked the StartUndo and it's using GeIsMainThreadAndNoDrawThread and just get out.
                    So it's pretty clear that you can't add undo on a thread.

                    why are you using thread here ?

                    Cheers,
                    Manuel

                    MAXON SDK Specialist

                    MAXON Registered Developer

                    A 1 Reply Last reply Reply Quote 0
                    • A
                      arsen @Manuel
                      last edited by

                      This post is deleted!
                      1 Reply Last reply Reply Quote 0
                      • A
                        arsen
                        last edited by

                        @m_magalhaes @zipit
                        I use thread to manipulate external pipes(subprocess etc).

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

                          @arsen said in AddUndo() for MergeDocument() ?:

                          @m_magalhaes @zipit
                          I use thread to manipulate external pipes(subprocess etc).

                          Hi,

                          although I am aware of the concept of pipes, this does not really clear anything up for me 🧐. What do you mean by external and manipulate? Just for clarification: Under pipes I understand a data IO interface to communicate between different processes, provided in Python for example by os.pipe().

                          And I don't really get why this forces you to use a thread to import an obj file 🤔.

                          Cheers
                          zipit

                          MAXON SDK Specialist
                          developers.maxon.net

                          A 1 Reply Last reply Reply Quote 0
                          • A
                            arsen @ferdinand
                            last edited by

                            @zipit
                            Hi
                            I use thread to track the external file. When a file is changed, it is imported.
                            When using c4d.threading, subprocess.Popen() / time.sleep() freezes C4D ( until the process is complete )

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

                              Hi,

                              ah, ok, I do understand your problem better now ;). Well as explained in this thread your cannot load files other than from the main thread of c4d.

                              You could do however the following:

                              1. Use processes, threads or whatever you would like to use to monitor the status of your file(s).
                              2. Use some cross-process communication interface like os.pipe() to indicate when your data has changed.
                              3. Implement 1. and 2. within a MessageData plugin.
                              4. Use MessageData.GetTimer and MessageData.CoreMessage to periodically peek into your pipe and then react to its status from the main thread/ the c4d process.

                              Cheers
                              zipit

                              MAXON SDK Specialist
                              developers.maxon.net

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

                                hello,

                                @zipit already make another nice answer.

                                I can just add that in c++ you have also a filemonitor manual where you can use the function WatchDirectory

                                Cheers,
                                Manuel

                                MAXON SDK Specialist

                                MAXON Registered Developer

                                1 Reply Last reply Reply Quote 0
                                • A
                                  arsen
                                  last edited by

                                  @zipit @m_magalhaes
                                  Thanks for the answers! I figured out how to solve the problem.

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

                                    hi,

                                    nice, feel free to share your solution and mark this thread as solved.

                                    Cheers,
                                    Manuel

                                    MAXON SDK Specialist

                                    MAXON Registered Developer

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