Solved ToolPlugin Problems

Hello!
I used utils.GeRayCollider in the ToolData.MouseInput() and ToolData.Draw() functions.
When the specified object is a high poly object then the scene will be calculated very slowly.
I don't know what causes this. Is there any way to optimize the codes?

This is my code:

def UnderCursor(self,doc,bd,mx,my,plane):
    """
    doc = Current document; 
    bd = Current BaseDraw
    mx = mouseX
    my = mouseY
    plane = The object to check for intersections.
    """

    pos = bd.SW(c4d.Vector(mx,my,0.1))     #screen to world conversion
    cam_pos = bd.GetSceneCamera(doc).GetAbsPos()

    pmg = plane.GetMg()
    pOlocal = cam_pos * ~pmg  
    p1local = pos * ~pmg  
    ldir = p1local-pOlocal
    
    collider = c4d.utils.GeRayCollider()
    collider.Init(plane,False)
    length = 2147483647
    direction = -(cam_pos - pos).GetNormalized()
    did_intersect = collider.Intersect(pOlocal, ldir, length)
    if did_intersect:
        p = collider.GetNearestIntersection()['hitpos']
        nrm = collider.GetNearestIntersection()['f_normal']
        dst = collider.GetNearestIntersection()['distance']
        mg = plane.GetMg()
        position = mg.Mul(p)
        

    return position,nrm,dst

def MouseInput(self, doc, data, bd, win, msg):
    mx = msg[c4d.BFM_INPUT_X]
    my = msg[c4d.BFM_INPUT_Y]

    device = 0
    if msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSELEFT:
        device = c4d.KEY_MLEFT
    elif msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSERIGHT:
         device = c4d.KEY_MRIGHT
    else:
        return True

    plane = doc.SearchObject("plane")
    
    c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION)
    dx = 0.0
    dy = 0.0
    
    win.MouseDragStart(button=device, mx=int(mx), my=int(my), flags=c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE|c4d.MOUSEDRAGFLAGS_NOMOVE)
    result, dx, dy, channel = win.MouseDrag()
    while result==c4d.MOUSEDRAGRESULT_CONTINUE:
        mx += dx
        my += dy

        position = self.UnderCursor(doc,bd,mx,my,plane)[0]

        c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION)
        result, dx, dy, channel = win.MouseDrag()

    if win.MouseDragEnd()==c4d.MOUSEDRAGRESULT_ESCAPE:

        doc.DoUndo(True)

    return True

def Draw(self, doc, data, bd, bh, bt, flags):
    bd.SetMatrix_Matrix(None, c4d.Matrix())

    bc = c4d.BaseContainer()
    gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc)
    mouse_x=bc.GetInt32(c4d.BFM_INPUT_X)
    mouse_y=bc.GetInt32(c4d.BFM_INPUT_Y)
    
    # Convert MouseCoordinates to Viewport Coordinates
    win= bd.GetEditorWindow()
    Editor_x, Editor_y = win.Global2Local()        
    mx = mouse_x-abs(Editor_x)
    my = mouse_y-abs(Editor_y)

    bd.SetPen(c4d.Vector(1))

    p = self.GetObj()[1]
    obj = self.GetObj()[0]
    dst = self.UnderCursor(doc,bd,mx,my,p)[2]
    off = self.UnderCursor(doc,bd,mx,my,p)[0]
    
    size = dst*0.005
    nrm = self.UnderCursor(doc,bd,mx,my,p)[1].GetNormalized()
    nrm_hpb = c4d.utils.VectorToHPB(nrm)
    rm = c4d.utils.HPBToMatrix(nrm_hpb)
    v1 = rm.v1*size
    v2 = rm.v2*size
    v3 = rm.v3*size
    mat = c4d.Matrix(off,v1,v2,v3)
    
    bd.DrawCircle(mat)

low poly fast;
fast.gif

high poly slow;
slow.gif

You are initialising the GeRayCollider every time you move your mouse. This rebuilds it every single time you move. Try moving the initialisation out of the UnderCursor method.

First try making the GeRayCollider a local variable of your tool and initialise it when you mouse click on the surface the first time. Then once you have that working look at detecting when the dirty flag changes and then you can initialize it again only when it is marked as dirty. Once you have that going then change it to doing this check when you activate your tool as well. Then update your code to perhaps work on all selected objects.

Hope that helps!
Kent

@kbar
First of all, thank you for your reply.
but I still don't quite understand, because I think if only after the mouse click to initialize, it seems that you can't Draw the circle in the viewport, because the ToolData.Draw() function needs to keep drawing the circle.
Could you can give me an example?

I was only suggesting small incremental steps to help you solve your problem. First step is to refactor your code so that the GeRayCollider is not being initialised every time you move your mouse. So the click to initialize is not your final end solution. Just a step to get you started to show you that the slow down is with the call to Init and that you need to find a place to initialize that only when you absolutely need to. You can still access it in the UnderCursor method, after it has been initialized, allowing you to get draw your cursor. Just iterate through the problem one step at a time. I will let other devs post up a working solution. I only jump in here and answer when I can and don't have much time to code up anything unfortunately.

@kbar
I get you point now, I thought too much before.
Thank you!
Cheers~🍻

@kbar
I've almost solved my problem!
Thank you again!

@gheyret great to hear! Looking forward to seeing what it is you are creating.