Hi All,
For our project we (@devmessias ) need to use timers that are executed in other threads and need to call some vtk functions on them. This works fine on Linux and Mac as the same OpenGL context can be shared across different threads. However on Windows, it seems that this is not allowed and there may be a need to clear the context after using it in a thread, and maybe initialize it correctly in the new thread. So my question is how to properly do this cleanup using python vtk?
Here is a example:
from threading import Timer
import numpy as np
import vtk
import time
class IntervalTimer:
def __init__(self, seconds, callback, *args, **kwargs):
"""Implements a object with the same behavior of setInterval from Js
Parameters
----------
seconds : float
A postive float number. Represents the total amount of
seconds between each call
callback : function
The function to be called
*args : args
args to be passed to callback
**kwargs : kwargs
kwargs to be passed to callback
"""
self._timer = None
self.seconds = seconds
self.callback = callback
self.args = args
self.kwargs = kwargs
self.is_running = False
self.start()
def _run(self):
self.is_running = False
self.start()
self.callback(*self.args, **self.kwargs)
def start(self):
"""Start the timer"""
if self.is_running:
return
self._timer = Timer(self.seconds, self._run)
self._timer.daemon = True
self._timer.start()
self.is_running = True
def stop(self):
"""Stop the timer"""
if self._timer is None:
return
self._timer.cancel()
if self._timer.is_alive():
self._timer.join()
self.is_running = False
self._timer = None
State = {'in_request': False}
def callback(*args, **kwargs):
print('init callback')
window2image_filter = kwargs['window2image_filter']
if State['in_request']:
return
State['in_request'] = True
window2image_filter.Update()
window2image_filter.Modified()
vtk_image = window2image_filter.GetOutput()
vtk_array = vtk_image.GetPointData().GetScalars()
# num_components = vtk_array.GetNumberOfComponents()
w, h, _ = vtk_image.GetDimensions()
np_arr = np.frombuffer(vtk_array, dtype='uint8')
if np_arr is None:
State['in_request'] = False
return
# do some stuff
print('callback finished')
State['in_request'] = False
colors = vtk.vtkNamedColors()
bkg = map(lambda x: x / 255.0, [26, 51, 102, 255])
colors.SetColor("BkgColor", *bkg)
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(8)
cylinderMapper = vtk.vtkPolyDataMapper()
cylinderMapper.SetInputConnection(cylinder.GetOutputPort())
cylinderActor = vtk.vtkActor()
cylinderActor.SetMapper(cylinderMapper)
cylinderActor.GetProperty().SetColor(colors.GetColor3d("Tomato"))
ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
ren.AddActor(cylinderActor)
ren.SetBackground(colors.GetColor3d("BkgColor"))
renWin.SetSize(300, 300)
renWin.SetWindowName('CylinderExample')
iren.Initialize()
window2image_filter = vtk.vtkWindowToImageFilter()
window2image_filter.SetInput(renWin)
timer = IntervalTimer(
1,
callback,
*[],
**{'window2image_filter': window2image_filter}
)
print('Timer created')
ren.ResetCamera()
ren.GetActiveCamera().Zoom(1.5)
renWin.Render()
time.sleep(1000)
This works on Linux and Mac but fails on Windows with:
2021-08-14 15:06:15.122 ( 1.718s) [ ]vtkWin32OpenGLRenderWin:217 ERR| vtkWin32OpenGLRenderWindow (000002DAF5AC0390): wglMakeCurrent failed in MakeCurrent(), error: The requested resource is
in use.
2021-08-14 15:06:15.168 ( 1.764s) [ ]vtkWin32OpenGLRenderWin:217 ERR| vtkWin32OpenGLRenderWindow (000002DAF5AC0390): wglMakeCurrent failed in MakeCurrent(), error: The requested resource is
in use.
thanks!