Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
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!
hello, you can simply add the document with c4d.UNDOTYPE_CHANGE
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
@m_magalhaes No, this solution does not work for me. I am trying to add UNDO when importing an OBJ file.
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
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
@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()
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:
c4d.threading.C4DThread
For all threaded functions it is forbidden to: Add an event. [...] Change the structure of objects attached to the document. [...] Create undos.
For all threaded functions it is forbidden to:
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.
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.
StartUndo
why are you using thread here ?
Cheers, Manuel
@m_magalhaes @zipit I use thread to manipulate external pipes(subprocess etc).
@arsen said in AddUndo() for MergeDocument() ?:
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().
os.pipe()
And I don't really get why this forces you to use a thread to import an obj file .
@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 )
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:
MessageData
MessageData.GetTimer
MessageData.CoreMessage
@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
@zipit @m_magalhaes Thanks for the answers! I figured out how to solve the problem.
nice, feel free to share your solution and mark this thread as solved.