EventAdd() doesn't update C4D



  • On 30/01/2013 at 07:57, xxxxxxxx wrote:

    Hi there,

    I have a problem with EventAdd. I have a cube and a cam. I check, if the cube is completely in view of the camera. If not, I step a bit away and test again. For the check I use the code from Yannick (see this thread: https://plugincafe.maxon.net/topic/6864/7679_dimensions-of-an-object-in-perspective-view&PID=31920#31920)
    In general this is my code:

        scaleFactor = c4d.Vector(cam.GetMg().off.x, cam.GetMg().off.y, cam.GetMg().off.z)  
      scaleFactor = scaleFactor.__mul__(0.05)  
        
      while not CheckIfInView(cam, cube, doc) :  
          camMg = cam.GetMg()  
          camMgOff = camMg.off  
          camMgOff += scaleFactor  
          camMg.off = camMgOff  
          cam.SetMg(camMg)  
          c4d.EventAdd()  
        
      c4d.CallCommand(12099) #render in pic viewer
    

    In CheckIfInView there is a conversion of worldcoordinates to screencoordinates. So when I move away from the object, the points have to change. But they don't, they stay the same, although the position of the camera is changing (checked in debugger).

    When I reposition the camera manually and check, if the cube is completely in view, all works fine. So my only suggestion is that EventAdd doesn't really update C4D.

    In general there is no update of the GUI, as long as I stay in a function. For example if I rotate my camera by 15° around an object, do an EventAdd(), take a render, rotate again and so on, there is no update till the complete script is over.

    So what can I do? Is it my fault or is EventAdd faulty?

    Thanks for any advice.



  • On 30/01/2013 at 08:48, xxxxxxxx wrote:

    scripts are single threaded. you can  work your way arround this, but it is not recommanded.
    use a plugin instead.

    edit : to be a bit more specific, you can of course create this function as script, but you 
    cannot use eventadd() in the way you want to use it. i also do not fully understand why 
    you want to call it for each loop, your camera matrix will be valid without it.

    edit2: ah ok i get it, i red the link, you will have either to set off the baseview matrix rather 
    than camera matrix before you call your method or you will have to do it threaded.



  • On 31/01/2013 at 04:15, xxxxxxxx wrote:

    Thank you for your reply littledevil. I tried to make a plugin out of my script. There occured several problems I'm pretty sure you can help me out.

    1. What do I have to do to get the plugin threaded? Because simply convert the script to a plugin doesn't do the trick for me, it's still an endless loop.

    2. I develop with Eclipse and use pydevd to remote debug. With scripts this works quite well, but when I try to use it in plugins C4D freezes at startup when it's loading the plugins. So how could i debug my code? How do you develop? I'm not restricted to Eclipse, so I'm open-minded ;)

    3. Do I really have to restart C4D after a change of my plugin code? Because "reload Python Plugins" don't recognise the changes and I have to restart C4D to get the changes to work.

    I would appreciate any suggestions :)

    €: And 4) What Plugin do I have to use for this kind of code? It's not really a CommandPlugin (as I saw in the examples these are for windows / GUI stuff [correct me if I'm wrong!]), it's definitely not an Object nor a Tool. It's just a few lines of code which should be executed when the user clicks on the icon. Where can I find informations, what each plugintype does? The API documentation says "Registers a ToolData plugin' or something like that, but never what the plugin is actually good for. You have to find it out by yourself. I have to say it is frustrating for a newcomer to Cinema 4D development to understand this whole system...



  • On 31/01/2013 at 08:08, xxxxxxxx wrote:

    The code you posted is confusing compared to the problem you say that you're having.
    You're saying the cube's points don't change. Yet your code is referring to scaling the camera's matrix.

    Ignoring the code you posted. A general rule is that if you change an object(move,scale, edit it's points, etc) you must use: "obj.Message(c4d.MSG_UPDATE)".
    You can often leave that code out. But in some cases it will prevent the object from updating properly.
    So it's best to get into the habit of using it.

    C4D has a million of these messages to deal with.
    These messages are scattered through the documentation. And not clearly stated in one central place when to use which one. Making it very hard for newbies.
    So just remember that every time you do something with code. You often have to tell the rest of C4D that you changed something.
    Sometimes you'll have to make this odd looking statement to get C4D to update properly: "c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK)".
    It depends on the situation.

    A command plugin (the GeDialog class) is basically the same thing as using the script manager.
    In the script manager you click the execute button to run the code.
    In a GeDialog plugin when you click on a gizmo that you made. It runs the code.
    They are both essentially the same thing. With the exception that the script manger has some limitations that a plugin doesn't have.

    Without seeing you entire code.
    If your workflow is to click a button and have the camera move and also have the cube change it's size at the same time. That can be done in the script manager without using a full blown plugin.
    It sounds like you just have to send the right update messages, and make sure you're doing things in the correct order.

    -ScottA



  • On 31/01/2013 at 08:28, xxxxxxxx wrote:

    hey,

    certain plugin methods are threaded per default. for all other you could either use native
    python threading classes or c4d.threading.(BaseThread) inside them. check the docs for 
    details. but you normally do not use EventAdd in plugins.

    for you specific problem, you should look ito c4d.BaseView.SetMatrix() it allows you to
    multiply you camera matrix. this can also be done from a script. you normally do not do 
    not work in incremental steps in plugins  or scripts (calc, update, calc, update ...) c4d calls
    your plugin/script methods on each pass, you collect your data, calaculate final result and 
    return it/write it.

    i use SublimeText2, i do not see any advantages in IDEs, they are just slow. debugging is 
    done with the c4d console.

    you do not have to restart c4d. exceptions are plugins which failed to register on the startup
    and changes to description based GUI elements. if you hve imported custom modules into
    your plugin you have to make sure that you reload the modules before you register the plugin,
    otherwise changes to the module files won't be reflected when you reload the python plugins
    until you restart c4d.



  • On 04/02/2013 at 05:21, xxxxxxxx wrote:

    Thanks for your kind replys! Sorry for replying so late, but there's so much work to do...

    @ScottA: I tried your Message functions and the second one do the trick. I post the entire code for better understanding what I try to achieve:

    import c4d  
    from c4d import documents  
      
    def TestPointInFrame(pt, frame) :  
      return pt.x > frame['cl'] and pt.x < frame['cr'] and \  
             pt.y > frame['ct'] and pt.y < frame['cb']  
      
    def CheckIfInView(cam, obj, doc) :  
      # Get the current BaseDraw  
      bd = doc.GetActiveBaseDraw()  
      safeFrame = bd.GetSafeFrame()  
            
      # Get the active object bouding box center and radius  
      
      box = [c4d.Vector() for x in xrange(8)]  
      points = [c4d.Vector() for x in xrange(8)]          
      
      
      rd = obj.GetRad()  
      mp = obj.GetMp()  
      
      # Build the active object bouding box  
      
      box[0] = c4d.Vector()  
      box[0].x = mp.x - rd.x  
      box[0].y = mp.y - rd.y  
      box[0].z = mp.z - rd.z  
      box[0] *= obj.GetMgn()  
        
      box[1] = c4d.Vector()  
      box[1].x = mp.x - rd.x  
      box[1].y = mp.y + rd.y  
      box[1].z = mp.y - rd.z  
      box[1] *= obj.GetMgn()  
        
      box[2] = c4d.Vector()  
      box[2].x = mp.x + rd.x  
      box[2].y = mp.y - rd.y  
      box[2].z = mp.y - rd.z  
      box[2] *= obj.GetMgn()  
        
      box[3] = c4d.Vector()  
      box[3].x = mp.x + rd.x  
      box[3].y = mp.y + rd.y  
      box[3].z = mp.y - rd.z  
      box[3] *= obj.GetMgn()  
        
      box[4] = c4d.Vector()  
      box[4].x = mp.x + rd.x  
      box[4].y = mp.y - rd.y  
      box[4].z = mp.z + rd.z  
      box[4] *= obj.GetMgn()  
        
      box[5] = c4d.Vector()  
      box[5].x = mp.x + rd.x  
      box[5].y = mp.y + rd.y  
      box[5].z = mp.y + rd.z  
      box[5] *= obj.GetMgn()  
        
      box[6] = c4d.Vector()  
      box[6].x = mp.x - rd.x  
      box[6].y = mp.y - rd.y  
      box[6].z = mp.y + rd.z  
      box[6] *= obj.GetMgn()  
        
      box[7] = c4d.Vector()  
      box[7].x = mp.x - rd.x  
      box[7].y = mp.y + rd.y  
      box[7].z = mp.y + rd.z  
      box[7] *= obj.GetMgn()    
        
      # Calculate bouding box coordinates in screen space  
        
      for i in xrange(len(box)) :  
          points[i] = bd.WS(box[i])  
        
      # Test if the current object is completely visible in the rendered safe frame  
        
      for i in xrange(len(points)) :  
          visible = TestPointInFrame(points[i], safeFrame)  
          if not visible:  
              break  
            
      return visible        
                        
      
    def main() :  
      doc = documents.GetActiveDocument()  
        
      cube = c4d.BaseObject(c4d.Ocube)  
      cube.SetName('Cube')  
      doc.InsertObject(cube)  
        
      cam = c4d.CameraObject()  
      cam.SetName('Cam')  
      camMg = cam.GetMg()  
      camMg.off = c4d.Vector(0,0,-200)  
      cam.SetMg(camMg)  
      doc.InsertObject(cam)  
        
      stage = c4d.BaseObject(c4d.Ostage)  
      doc.InsertObject(stage)  
      stage[c4d.STAGEOBJECT_CLINK] = cam  
        
      cube.SetBit(c4d.BIT_ACTIVE)  
        
      scaleFactor = c4d.Vector(cam.GetMg().off.x, cam.GetMg().off.y, cam.GetMg().off.z)  
      scaleFactor = scaleFactor.__mul__(0.05)  
        
      while not CheckIfInView(cam, cube, doc) :  
          camMg = cam.GetMg()  
          camMgOff = camMg.off  
          camMgOff += scaleFactor  
          camMg.off = camMgOff  
          cam.SetMg(camMg)  
          c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK)  
        
      c4d.CallCommand(12099)  
      
      
    if __name__ == '__main__':  
      main()
    

    Please keep in mind that this is a "quick and dirty" approach. I know that it is bad habit to calculate things incrementaly but I don't get it. So I used this approach to show, what I want to get.
    Has anyone an idea, how I can simply calculate the final position of the camera to get the same result as in my approach?

    @littledevil:
    I read the documentation for threads in c4d several times, but I can't see why I have to use them. When I look at the forbidden functions then I can't see anything that would help me with my problems. There won't be any time consuming calculations. The only time consuming things are merging documents and render pictures.Also the flow is strictly linear (import this file, merge that one, do some adjustments there, safe the file and render all of that). So there's nothing worthy what I can split in other threads.

    I just want a bit of a response of c4d that it is working while importing 100 files in a loop. All i want is a quick print to the console, but can't get it to work. And/or an update of the object manager after each merge would be very nice. Is there something like Scott's obj.Message(c4d.MSG_UPDATE) for the console or the OM? Can't find anything in the documentation and on the web.

    You mentioned that I have to reload my plugin modules first, if I have changed something. I remember that I saw a code snippet which forces c4d to exactly do this with a list of the modules which must be reloaded, but I can't find it anymopre. Do you have an idea how this code should look like?

    Any help would be really appreciated!

    €: Ok, I managed to convert my script to a plugin. And YEAH! The console updates properly! :D
    But an update of the OM would still be very nice to have :) Are there any possibilities?

    €2: Damn it! The update of the console worked perfectly fine for lets say 20 times. I changed NOTHING and now it doesn't update any more! I haven't changed one line of code! I just screencaptured the process with Camtasia a few times. What is this?!?



  • On 04/02/2013 at 13:08, xxxxxxxx wrote:

    You are trying to incrementally move a camera until the object in the view is within the safeFrame.
    The key word here being "incrementally".

    EventAdd() does different things depending on how and where you're using it.
    If you use EventAdd() in the Script Manager. It will usually only help to update the things you're doing. Like adding an object then using it to tell C4D that a major change has occurred.
    But it won't run your entire loop again where you're moving something inside of it.
    Once a loop runs in the Script Manager that's it. There's no going back to it (normally).
    It's not really designed to move things incrementally.
    The Script Manager is more of a one shot per click of the "execute" button kind of deal.

    Python tags and plugins are different.
    Every time you move the timeline scrubber. The code in your python tags or plugin gets executed.
    Including the loop that moves something in your code. Which allows it to move incrementally. Not just once.
    If you use EventAdd() in a python tag. It also makes your entire script run over, and over, and over again. Just like if the time scrubber is running.
    This is how to make an object incrementally move. Even if the scrubber isn't moving.
    But that also means that you have to treat the entire python tag like one big while loop. And have some kind of a "break" in the code to tell it where to stop executing code if camera is in the desired place.

    -Creation of things is most commonly done with a script in the script manager.
    -Incrementally moving things is generally done with a python tag using EventAdd() or the time scrubber to make the code execute over & over...
    -A plugin lets you combine these two things into the same workspace

    -ScottA



  • On 05/02/2013 at 00:48, xxxxxxxx wrote:

    Thank you very much for your explanation ScottA! This gives my a good insight of what's going on.

    But I don't want to do this incrementally. This was only an approach, because I think I can't myself understandable enough. After all I want to move my camera (in negative z-axis) away from my object in a way, that the whole object is rendered properly. So just like what the code above does but only in one single step (which solves the c4d.EventAdd() problem by itself). But I can't get managed to calculate the correct position of the camera and I don't know why. So any help would be very appreciated!
    Also I'd be very glad to see some answers for my other questions I asked in my post above.

    Thank you for your time!



  • On 05/02/2013 at 01:03, xxxxxxxx wrote:

    Hi Nachtmar,
    I found this very useful, maybe it will help you too. I was fighting with positions etc. until I dound this:
    http://www.nerdingoff.com/2012/02/c4d-python-matrix-basics-helper.html
     
    -Ingvar



  • On 05/02/2013 at 09:52, xxxxxxxx wrote:

    You may not want it to be incremental. But that's how your code is set up.🙂
    Your code has a while loop in it that moves the camera if the object is not within the safeFrame view.

    The code that Yannick provided requires this kind of workflow to use it:
    -Check if object is fully in frame
    -if not: Move the object or the camera by some small amount
    -Check again if object is fully in frame
    -Repeat until object is fully in frame

    The incremental moving of the object or camera and then checking it again the scene view requires this to be done in a python tag or plugin. Where the code can run multiple times.
    It's not something you can normally do in the Script Manager script.

    This is a much more common way of placing objects in front of a camera using a script. And it's a lot less code to write:

    import c4d  
    from c4d import utils  
    def main() :  
      
      obj   = doc.GetActiveObject()             #The object to move  
      if obj is None: return False  
        
      box = obj.GetRad()                        #The object's bounding box radius  
      
      bd  = doc.GetActiveBaseDraw()  
      
      cam = bd.GetSceneCamera(doc)  
      camMtx = cam.GetMg()  
      
      #Something to compare the camera to the object..Use whatever camera property you want  
      focus = cam[c4d.CAMERAOBJECT_TARGETDISTANCE]  
      
      #This is what's commonly called a "translation matrix"      
      offset = c4d.utils.MatrixMove(c4d.Vector(0, 0, box.z + focus/7.5))  
      
      newmtx = camMtx * offset  
        
      obj.SetMg(newmtx)                         #Move the object to same place as the camera  
      
      obj.Message(c4d.MSG_UPDATE)               #Update the change made to the object  
      c4d.EventAdd()                            #Update C4D that something changed in the scene  
      
    if __name__=='__main__':  
      main()
    

    -ScottA



  • On 06/02/2013 at 01:42, xxxxxxxx wrote:

    Thanks for your replies!
    @ingvair: I'll have a deeper look into this, thank you!

    @ScottA: Thanks for the code, but I believe that I'm still misunderstood. I'll try it this way if you don't mind:

    1. I never wanted to do the code incrementaly, I want to do this with one single calculation
    2. You move the object, I want to move my camera (away from the object)
    3. you turn the object to the camera, I want to keep the angle between camera and object
    4. basically I want the same effect as when I press 'H' on the keyboard, but in a controlled way, so that the selected object is completely in the rendered frame but with its maximal size.

    Here's a picture for more explanation:
    https://sharedspace.uhlmann.de/download2.php?fileid=oqy02MUHr6



  • On 06/02/2013 at 03:20, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Thanks for your replies!
    @ingvair: I'll have a deeper look into this, thank you!

    @ScottA: Thanks for the code, but I believe that I'm still misunderstood. I'll try it this way if you don't mind:

    1. I never wanted to do the code incrementaly, I want to do this with one single calculation
    2. You move the object, I want to move my camera (away from the object)
    3. you turn the object to the camera, I want to keep the angle between camera and object
    4. basically I want the same effect as when I press 'H' on the keyboard, but in a controlled way, so that the selected object is completely in the rendered frame but with its maximal size.

    Here's a picture for more explanation:
    https://sharedspace.uhlmann.de/download2.php?fileid=oqy02MUHr6

    Without wanting to sound rude, but you still do not understand. As I wrote already earlier you
    have to offset your basedaraw matrix, and I think Scott suggested something similar. You are in 
    some kind of special scenario, you want to calculate view related data. The base view class 
    depends on your camera matrix. Your approach was something like this :

    1. calculate data
    2. check result
    3. update the whole scene
    4. on false : goto 1
    5. on true : exit

    This is an incremental approach. Which is not generally bad, but in combination with updating the
    GUI (moving the camera  to update the base data for the base view) it leads to several problems.

    As I wrote earlier, simply use c4d.BaseView.SetMatrix() it has been made for this exact scenario,
    to offset a baseview.

    ps : i am littledevil :)



  • On 06/02/2013 at 03:28, xxxxxxxx wrote:

    @Scott: Putting the code into a tag would be necessary when the camera should
    be moved or just be influenced over time (animated), but not when the camera should
    be moved for workflow reasons (like Nachtmahr said the 'H' command)

    -Niklas



  • On 06/02/2013 at 04:38, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Without wanting to sound rude, but you still do not understand.

    You don't sound rude, I can't deny that I still don't understand this ;) But I'm eager to learn so I'll ask as long as I get the problem solved :]

    Originally posted by xxxxxxxx

    As I wrote earlier, simply use c4d.BaseView.SetMatrix() it has been made for this exact scenario, to offset a baseview.

    I'm sure you mean c4d.BaseView.SetBaseMatrix() because your method doesn't exist. I don'r understand what this method does. The documentation says "Sets the base matrix." - well... I already guessed that... The note says "The base matrix is multiplied with the camera matrix so that it is possible to have e.g. a frontal view into another direction than +Z."
    Ok, so it is multiplied with my camera matrix. I tried it in changing the BaseMatrix via the console

      
    bd = doc.GetActiveBaseDraw()  
    bm = bd.GetBaseMatrix()  
    vec = c4d.Vector(0.1, 0, 0)  
    bm.off = vec  
    bd.SetBaseMatrix(bm)  
    

    I expected to see a change in view (because it is multiplied with my camera matrix as mentioned above) or something like that or at least in a rendering, but nothing happens.
    So I'm sorry, I still don't understand what this matrix does or how I have to use it. If you can give me a short example I'd be very glad!

    Thanks in advance
    Nachtmahr



  • On 06/02/2013 at 05:44, xxxxxxxx wrote:

    Nachtmar,
     
    have a look at this:
    http://chicagoc4d.com/C4DPythonSDK/misc/matrixfundamental.html#matrix-fundamental
     
    and did you look at the link I sent you in my prevoius post?
    I struggled with similar things a few days ago. This helped me.
     
    -Ingvar



  • On 06/02/2013 at 13:22, xxxxxxxx wrote:

    I feel like I'm not being clear enough about why you can't (normally) do this kind of thing with a script.
    You are comparing an object's points to a camera's position. Which means that you have to physically have these objects in the scene to do the comparison. It can't be done virtually in memory where the user doesn't see this happening unless the whole thing is done in a separate document.

    This kind of thing is much easier to do in a python tag. Because you can re-run the entire code just by using EventAdd() until the condition you're testing for becomes true.
    You don't have this option in a script. It runs once then you're done.
    There is no such thing as: Test the objects->Move one of the objects->Test the objects again etc. until you get the desired result.
    You can't do that in a script.

    However. That said you can force a script to do this kind of thing.
    But it's a lot of extra work. And it requires a lot of adding and removing objects.
    Which might not be considered a good practice.

    This script will position the camera so the cube is within the safeFrame view.
    And it does it in one click:

    import c4d  
      
    def TestPointInFrame(pt, frame) :  
      return pt.x > frame['cl'] and pt.x < frame['cr'] and \  
             pt.y > frame['ct'] and pt.y < frame['cb']  
      
    def CheckIfInView(cam, obj, doc) :  
      #Get the current BaseDraw  
      bd = doc.GetActiveBaseDraw()  
      safeFrame = bd.GetSafeFrame()  
            
      #Get the active object bouding box center and radius  
      box = [c4d.Vector() for x in xrange(8)]  
      points = [c4d.Vector() for x in xrange(8)]  
      rd = obj.GetRad()  
      mp = obj.GetMp()  
      
      #Build the active object bouding box  
      box[0] = c4d.Vector()  
      box[0].x = mp.x - rd.x  
      box[0].y = mp.y - rd.y  
      box[0].z = mp.z - rd.z  
      box[0] *= obj.GetMgn()  
        
      box[1] = c4d.Vector()  
      box[1].x = mp.x - rd.x  
      box[1].y = mp.y + rd.y  
      box[1].z = mp.y - rd.z  
      box[1] *= obj.GetMgn()  
        
      box[2] = c4d.Vector()  
      box[2].x = mp.x + rd.x  
      box[2].y = mp.y - rd.y  
      box[2].z = mp.y - rd.z  
      box[2] *= obj.GetMgn()  
        
      box[3] = c4d.Vector()  
      box[3].x = mp.x + rd.x  
      box[3].y = mp.y + rd.y  
      box[3].z = mp.y - rd.z  
      box[3] *= obj.GetMgn()  
        
      box[4] = c4d.Vector()  
      box[4].x = mp.x + rd.x  
      box[4].y = mp.y - rd.y  
      box[4].z = mp.z + rd.z  
      box[4] *= obj.GetMgn()  
        
      box[5] = c4d.Vector()  
      box[5].x = mp.x + rd.x  
      box[5].y = mp.y + rd.y  
      box[5].z = mp.y + rd.z  
      box[5] *= obj.GetMgn()  
        
      box[6] = c4d.Vector()  
      box[6].x = mp.x - rd.x  
      box[6].y = mp.y - rd.y  
      box[6].z = mp.y + rd.z  
      box[6] *= obj.GetMgn()  
        
      box[7] = c4d.Vector()  
      box[7].x = mp.x - rd.x  
      box[7].y = mp.y + rd.y  
      box[7].z = mp.y + rd.z  
      box[7] *= obj.GetMgn()    
        
      #Calculate bouding box coordinates in screen space      
      for i in xrange(len(box)) :  
          points[i] = bd.WS(box[i])  
        
      #Test if the current object is completely visible in the rendered safe frame      
      for i in xrange(len(points)) :  
          visible = TestPointInFrame(points[i], safeFrame)  
          if not visible:  
              break  
            
      return visible        
                        
    Zvalue = 0  
    def main() :  
      global Zvalue  
        
      cube = c4d.BaseObject(c4d.Ocube)  
      cube.SetName('Cube')  
      doc.InsertObject(cube)  
      cube.SetBit(c4d.BIT_ACTIVE)  
      c4d.CallCommand(12236) # Make Editable  
        
      cam = c4d.CameraObject()  
      cam.SetName('Cam')  
      camMg = cam.GetMg()  
      camMg.off = c4d.Vector(0,0,-200)  
      cam.SetMg(camMg)  
      doc.InsertObject(cam)  
        
      stage = c4d.BaseObject(c4d.Ostage)  
      doc.InsertObject(stage)  
      
      count = 0  
      while count< 150:   #<--------------- Force the loop to stop after a set amount for safety  
          tempcam = c4d.BaseObject(c4d.Ocamera)  
          doc.InsertObject(tempcam)  
          pos = tempcam.GetAbsPos()  
          tempcam.SetAbsPos(c4d.Vector(0, 0, Zvalue - 3))  
          tempcam.Message(c4d.MSG_UPDATE)  
          pos = tempcam.GetAbsPos()  
          Zvalue = pos.z  
          stage[c4d.STAGEOBJECT_CLINK] = tempcam  
          c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK)  
          if CheckIfInView(cam, cube, doc) :break  
          tempcam.Remove()              
          #print Zvalue        
          count +=1  
            
            
      #Set the original camera to the position the last cloned camera version was    
      cam.SetAbsPos(c4d.Vector(0,0, Zvalue))      
                
      c4d.EventAdd()  
      
    if __name__ == '__main__':  
      main()
    

    Quite a mouthful of code for such a seemingly simple task ain't it. 😉

    -ScottA



  • On 06/02/2013 at 15:05, xxxxxxxx wrote:

    Hi,

    it is also possible without calling DrawViews() by moving the object itself, taking the delta from
    its original position, move the camera by this delta and reset the object.

    import c4d
      
    def TestPointInFrame(pt, frame) :
        return pt.x > frame['cl'] and pt.x < frame['cr'] and \n           pt.y > frame['ct'] and pt.y < frame['cb']
      
    def CheckIfInView(obj, bd) :
        safeFrame = bd.GetSafeFrame()
      
        #Get the active object bounding box center and radius
        box = [c4d.Vector() for x in xrange(8)]
        rd = obj.GetRad()
        mp = obj.GetMp()
      
        #Build the active object bouding box
        box[0].x = mp.x - rd.x
        box[0].y = mp.y - rd.y
        box[0].z = mp.z - rd.z
        box[0] *= obj.GetMgn()
      
        box[1].x = mp.x - rd.x
        box[1].y = mp.y + rd.y
        box[1].z = mp.y - rd.z
        box[1] *= obj.GetMgn()
      
        box[2].x = mp.x + rd.x
        box[2].y = mp.y - rd.y
        box[2].z = mp.y - rd.z
        box[2] *= obj.GetMgn()
      
        box[3].x = mp.x + rd.x
        box[3].y = mp.y + rd.y
        box[3].z = mp.y - rd.z
        box[3] *= obj.GetMgn()
      
        box[4].x = mp.x + rd.x
        box[4].y = mp.y - rd.y
        box[4].z = mp.z + rd.z
        box[4] *= obj.GetMgn()
      
        box[5].x = mp.x + rd.x
        box[5].y = mp.y + rd.y
        box[5].z = mp.y + rd.z
        box[5] *= obj.GetMgn()
      
        box[6].x = mp.x - rd.x
        box[6].y = mp.y - rd.y
        box[6].z = mp.y + rd.z
        box[6] *= obj.GetMgn()
      
        box[7].x = mp.x - rd.x
        box[7].y = mp.y + rd.y
        box[7].z = mp.y + rd.z
        box[7] *= obj.GetMgn()
      
        #Calculate bouding box coordinates in screen space
        points = [bd.WS(p) for p in box]
      
        #Test if the current object is completely visible in the rendered safe frame
        for i in xrange(len(points)) :
            if not TestPointInFrame(points[i], safeFrame) :
                return False
      
        return True
      
    def MoveObjectRel(op, axis, offset) :
        axis = axis.GetNormalized()
        axis.off = op.GetRelPos()
        op.SetRelPos(axis * offset)
      
    def EscapePressed(bc=None) :
        if bc is None:
            bc = c4d.BaseContainer()
            c4d.gui.GetInputEvent(c4d.BFM_INPUT_KEYBOARD, bc)
        return bc[c4d.BFM_INPUT_CHANNEL] == c4d.KEY_ESC
      
    def main() :
        if not op:
            c4d.gui.MessageDialog("please select an object")
            return
      
        bd = doc.GetActiveBaseDraw()
        cam = bd.GetSceneCamera(doc)
        if op is cam:
            return MessageDialog("can not apply on the cam")
      
        campos = cam.GetAbsPos()
        pos = op.GetAbsPos()
        axis = cam.GetMg()
        offset = c4d.Vector(0, 0, 10)
      
        # Create an undo-state for the camera because we will offset it.
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, cam)
        c4d.StatusSetSpin()
      
        passes = 0
        stopped = False
        while not CheckIfInView(op, bd) :
            stopped = EscapePressed()
            if stopped: break
      
            MoveObjectRel(op, axis, offset)
            passes += 1
      
        delta = op.GetAbsPos() - pos
        op.SetAbsPos(pos)
      
        if not stopped:
            campos -= delta
        cam.SetAbsPos(campos)
      
        c4d.StatusClear()
        c4d.EventAdd()
      
    main()
    


  • On 08/02/2013 at 05:34, xxxxxxxx wrote:

    Thank you for your wonderful codes! I experimented the last two days with them and still have a few questions about them.

    @Scott: You said, that scripts should not be used for this and that I should use a plugin instead. I'm quite open to that but I'm not really sure what the significant changes regarding your code will be. Can I use a complete new (and simpler) approach when using PlugIns? If so, what will it look like? I'm sorry if you had this question already answered, but I still have problems with that.

    @Niklas: You move the object, not the camera. In future the scene I'll use this script/plugin on will have about 18.000 objects. I couldn't test it yet, but i suppose that this will be a serious performance issue.
    And you use this line of code "op.SetRelPos(axis * offset)" to set the new offset of the object. If I'm not completely wrong vector math dictates to add the two vectors to get the resulting vector, not to multiply them. Obviously your solution works, so can you please tell me, why you multiply these two vectors instead of adding them? I'm really confused about this fact...

    I really appreciate all your input and you all are helping me a lot! I'm really looking forward for your further answers. Thanks in advance!



  • On 08/02/2013 at 05:46, xxxxxxxx wrote:

    Hi Nachtmahr,

    I am moving the object, because moving the camera would require to redraw the editor in order for
    BaseDraw.WS() to work correctly. The result is exactly the same. Compare Scotts and mine
    example. You can watch the editor slowly moving away from the object in Scotts code, mine works
    almost instantly. Do you really think it is more performant to redraw the editor on each pass?

    axis is not a vector, it is a matrix. I'm moving the object away from the camera to simulate a
    "zooming out". After the object is far away enough to fit into the editor view, I reset it to its
    original position and move the camera about the anmount the object was moved in negative
    direction.

    > >> In future the scene I'll use this script/plugin on will have about 18.000 objects.

    Separately or all at once (so they all fit into the view at once)? Make CheckInView() traverse the
    hierarchy recursively to check if all objects in the scene are in the frame. You should put all
    objects under a Null-Object then (to make the simulation of "zooming out" work) assuming you
    keep sticking to my solution.

    -Niklas



  • On 08/02/2013 at 06:15, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Separately or all at once (so they all fit into the view at once)?

    It's a machine imported from a CAD-Tool for rendering. In most cases I have to render seperate parts of the whole machine, so the focusing will affect multiple thousands of objects, but not all of them.

    Originally posted by xxxxxxxx

    You should put all objects under a Null-Object then (to make the simulation of "zooming out" work)

    I think this won't be possible, because the inner structure of the imported data has to be kept. And if I move the parts under a Null-object I have to seperate them to their old places after the focusing is done. This sounds a bit of overkill to me.


Log in to reply