Python: "Frame Selected" Within a Thread
-
Using Python, I'm trying to "Frame Selected" for the current camera while running within a Thread.
class procThread(c4d.threading.C4DThread): ...
When I run either of these two commands from outside the Thread, they work fine:
c4d.CallCommand(5103)
or
c4d.CallCommand(12151)
followed by this for safety:
c4d.EventAdd()
But if I run these commands from inside the Thread, the framing doesn't occur. I need a Thread so the user can have a progress bar while I iterate over loading a bunch of objects, framing each object and rendering it. Everything is working except for the framing. Any helpful suggestions would be much appreciated! Perhaps it's just not possible? Thanks!
-
Hi @flewis,
welcome to the forum and the Cinema 4D development community. Thank you for reaching out to us. The reason why you cannot frame a camera form within your thread is that you are there ultimately caught in its thread environment and these come with certain limitations; specifically to carry out anything GUI related and adding events, which you will need when trying to frame an object.
The solution to your problem would be to decouple your asynchronous from the interface layer, i.e., move the framing of objects into the main thread where you can do this. However, depending on the design of your code this might result in you having to wait so often for the main thread within your custom thread, that it might be more reasonable to:
- just either implement everything in the main thread or
- alternatively scrap the "constant live updating"-feature of your code in favour of running it asynchronously to the main thread (which has it limitations in Python anyways).
An alternative could be to try to use pipes or semaphores, i.e., something that is being shared between threads to convey information, but that can be tricky to be done from scratch and the ones provided by Python and intended for its asynchronous features probably won't work with Cinema 4D's threads (have not tried yet, I might be wrong). You might also be able to just get away with a carefully used
BaseContainer
as a signal object, but this is pure speculation on my side.Please also note, that we require users on this forum to tag their postings with support relevant tags like the version of Cinema, the used language and more. The feature is explained in the Forum Guildines. I have done some of it for you here, but you still need to add your Cinema version and OS.
Cheers,
Ferdinand -
Thank you for your helpful info @zipit and for responding so quickly! This gives me a few alternatives to explore!
I'm also thinking of alternatives to using the built in "frame selected" functionality at all, with something like this general approach:
- Get the bounding box center of all the geo, collectively, by using BaseObject.GetMp for each object and finding the maximum and minimum x, y and z center values gotten for all objects, and then finding the midpoint of those max and min values.
- Get the bounding box radius for all geo, collectively, using a similar approach to that of step 1, using BaseObject.GetRad.
- Get the viewing angle of the camera.
- Point the camera at the bounding box center and move it far enough away from that point to include the collective bounding box given the viewing angle.
Sorry about not adding the tags. I currently don't seem to have access to the guidelines. When I try to go to this link https://plugincafe.maxon.net/guidlines_cp either by clicking the exclamation point icon at the top of the forum page or by pasting the link address directly, I get:
"Access Denied
You seem to have stumbled upon a page that you do not have access to."I have added the tags you mentioned.
I am marking this as "solved" since you have answered my question.
Thanks.
Fred
-
Hi @flewis,
sorry, there has been some mix-up with access rights, you should be now able to access the page. About your fix: It does not really matter if you do it manually or not. While you can decouple the modification of the node attributes - which is allowed from within a thread - from the redraw event, to carry out that newly computed camera transform, you still will have to invoke a redraw, which you cannot do from within your threaded environment. When you invoke such redraw event, the first thing the internal code does, is to check if its running on the main thread and if not, it just gets out. So there is not much won by doing it manually, at least for what from my understanding is the premise of your problem: To constantly frame the viewport to the object that is currently processed by your async code.
Cheers,
Ferdinand