Threading for modelling tools

  • On 18/05/2013 at 11:26, xxxxxxxx wrote:


    I have a pretty diffuse question again. I have a ToolData plugin which modifies the point data of 
    a polygon object attached to the active document. The plugin has a GeDialog gui and also allows
    modifying the main value by dragging in the editor window. The plugin is working technically 
    working fine, but there is still the problem that when I drag a gui slider or live drag in the editor
    window, that update method is not executed until i do release the mouse button. I guess the
    the reason is that i do all calculations from the main thread.

    So are there any resources on how to implement threading for such a task (i have to admit
    that i have generally avoided threading until now).

    here a visual help, if it was difficult to understand  my description of the problem :


    While dragging (without update) :

    Update after releasing the mouse button:

    Thanks for reading,
    Happy rendering,

  • On 19/05/2013 at 07:57, xxxxxxxx wrote:

    Is something unclear about my question ? It seems to be rather common problem for me. At
    least in python I am not sure if ToolDescriptionData behaves differently in cpp. What I do
    really not understand is why there is no update at all while I am dragging, instead of a
    sluggish GUI/update behaviour because I do run everything from one thread.

    If some code helps for giving me an answer, I will try to show the update cycle on the
    example of an editor view mouse drag. The tool is working with a cache of the objects
    point and polygon data, so you can drag the sliders back and forth and they will always
    relate to the state when the tool has been raised.

        # --- Implements value mouse/editor manipulation and cursor change while drag event. 
        # -----------------------------------------------------------------------------------------------
        def MouseInput(self, doc, data, bd, win, msg) :
            startbc, currentbc, ox, dv = c4d.BaseContainer(), c4d.BaseContainer(), None, None
            # starting mouse state
            isok = gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, startbc)
            # start drag
            if isok and startbc[c4d.BFM_INPUT_VALUE]:
                sx = startbc.GetLong(c4d.BFM_INPUT_X)
                # loop while mouse drag
                while gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, currentbc) :
                    if currentbc.GetLong(c4d.BFM_INPUT_VALUE) == 0: break
                    x = currentbc.GetLong(c4d.BFM_INPUT_X)
                    # change dialog values when x != ox
                    if self.Dialog and x != ox:
                        # reset sx if drag vector changed
                        if dv != None and (dv>0) != (x-ox > 0) : sx = x
                        # check for shift qualifier and adjust dragscale
                        if currentbc[c4d.BFM_INPUT_QUALIFIER] == c4d.QSHIFT: 
                            scale = fhPolyTools.ID_MOUSE_DRAGSMALL
                        else : scale = fhPolyTools.ID_MOUSE_DRAGBIG
                        # edit the dialog value with the mouse data
                        dialogvalue = self.Dialog.GetReal(fhPolyTools.IDC_STRAIGHTEN_STRENGHT_EDT)
                        value  = round(c4d.utils.Clamp(0.001, 1, dialogvalue + ((x - sx) * 0.01) * scale), 4)
                        self.Dialog.SetPercent(id = fhPolyTools.IDC_STRAIGHTEN_STRENGHT_EDT, value = value, 
                                               min = 0.0, max = 100.0, step = 0.01, tristate = False)
                        # set dragvector and last pos
                        if ox: dv = x - ox
                        ox = x
                # set cursor back
            return isok

    the orange line calls GeDialog.Update() in my tools dialog, which then simply calls back to the 
    tool itself:

        def Update(self) :
            return self.Host.Update(strenght     = self.GetReal(fhPolyTools.IDC_STRAIGHTEN_STRENGHT_EDT), 
                                    relax        = self.GetReal(fhPolyTools.IDC_STRAIGHTEN_RELAX_EDT), 
                                    distribution = self.GetReal(fhPolyTools.IDC_STRAIGHTEN_UNIFORM_CHK))

    the ToolData.Update() method loops through some earlier processed ordered point data to 
    apply the transform method ToolData.straightenEdge() which then updates the  point array 
    of the object which is then written into the object. undos are currently implemented in 
    other methods.

        # --- Update method called by the dialog and mouse input
        # --> Bool
        # -----------------------------------------------------------------------------------------------
        def Update(self, strenght, relax, distribution) :
            doc = documents.GetActiveDocument()
            if self.GetData(doc) :
                # copy cache
                data = self.PointCache[:]
                for pointgroup in self.PointGroups.PointGroups:
                    data = self.straightenEdge(data, pointgroup, strenght, True)
                    if not data: return False
                # update object
                return True
            return False

    so which part do i have to put into a thread ?

  • On 19/05/2013 at 09:44, xxxxxxxx wrote:

    Hi littledevil,

    you say the mesh doesn't update while dragging a slider, did I get this straight?
    From the code you have posted, I only see you are doing the operations in MousInput().
    This method is not called while you are dragging a slider in the dialog, you need to
    override the Command() method of the dialog in this case.


  • On 19/05/2013 at 10:01, xxxxxxxx wrote:

    the example posted above is for ToolData.MouseInput(). The example shows the
    case where you chanage the 'main' value (the tools strength) by draginng with 
    the mouse pointer into a editor view. Just like you can do it for the extrude tool for 

    I have of course also overwritten GeDialog.Command() to register changes made
    in the GeDialog gui. The update behaviour for that is the same.

    # ----------------------------------------------------------------------------------------------- def Command(self, cid, msg) : # Endable/disable apply button if cid == fhPolyTools.IDC_TOOL_REALTIME_CHK: self.Realtime = self.GetBool(fhPolyTools.IDC_TOOL_REALTIME_CHK) self.Enable(fhPolyTools.IDC_TOOL_APPLY_BTN, not self.Realtime) # Apply update if cid == fhPolyTools.IDC_TOOL_APPLY_BTN: self.Update() # Reset values if cid == fhPolyTools.IDC_TOOL_RESET_BTN: self.InitValues() # Invoke update if realtime if self.Realtime: self.Update() return True

  • On 19/05/2013 at 10:14, xxxxxxxx wrote:

    I see. Try DrawViews() instead/in addition to EventAdd(). Threading
    wouldn't help at all.


  • On 19/05/2013 at 10:28, xxxxxxxx wrote:

    three things :

    1. when dragging in the editor window with the mouse the GeDialog slider is actually
    updatetd properly while dragging

    2. i also tried calling c4d.StopAllThreads() before updating the object, but it had no effect

    3. i already wrote it earlier, what bugs me most, is that the problem is not that everything 
    is very slow, as i am doing verything from one thread, but that it runs smoothly, only that
    the result of the modification is not shown until i release the left mouse button (both for
    the editor and the dialog slider).

    so it feels somehow that c4d limits the update of obejcts while some mouse interaction
    is going on. but i am not sure how for example the extrude tool is avoiding that problem.
    is the object shown by those tools in the editor maybe actually not the object attached 
    to the document, but only a reflection of the tools data cache drawn with the tools Draw()
    method ?

  • On 19/05/2013 at 10:31, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I see. Try DrawViews() instead/in addition to EventAdd(). Threading
    wouldn't help at all.


    that did the trick, god and i saw myself already sunken into some nasty threading geek stuff.


    happy rendering,

Log in to reply