33import os
44import asyncio
55import time
6- from abc import ABC , abstractmethod
76from asyncio import Queue
87from concurrent .futures .thread import ThreadPoolExecutor
98from concurrent .futures import Executor
109from enum import Enum
11- from packaging .version import Version
12- from typing import Callable , Optional
10+ from typing import Callable , Optional , TYPE_CHECKING
1311
1412from numpy .typing import NDArray
1513from trame .app import asynchronous
16- from vtkmodules .util .numpy_support import vtk_to_numpy
17- from vtkmodules .vtkRenderingCore import vtkRenderWindow , vtkWindowToImageFilter
18- import json
1914from trame_rca .encoders .pil import encode as encode_pil
2015
21- from vtkmodules .vtkCommonCore import vtkCommand , vtkVersion
22- from vtkmodules .vtkWebCore import vtkRemoteInteractionAdapter
16+ if TYPE_CHECKING :
17+ from vtkmodules .vtkRenderingCore import vtkRenderWindow
18+
19+ from trame_rca .protocol import AbstractWindow
20+
21+ try :
22+ from trame_rca .vtk_utils import VtkWindow
23+ except ModuleNotFoundError as e :
24+ print (e .msg )
2325
2426try :
2527 from trame_rca .encoders .turbo_jpeg import encode as encode_turbo
3234
3335ENCODING_POOL = ThreadPoolExecutor (max (4 , os .cpu_count ()))
3436
37+ __all__ = [
38+ "AbstractWindow" ,
39+ "RcaEncoder" ,
40+ "RcaViewAdapter" ,
41+ "RcaRenderScheduler" ,
42+ "VtkWindow" ,
43+ ]
44+
3545
3646def time_now_ms () -> int :
3747 return int (time .time_ns () / 1000000 )
@@ -40,8 +50,12 @@ def time_now_ms() -> int:
4050def window_wrapper (window : AbstractWindow | vtkRenderWindow ) -> AbstractWindow :
4151 if isinstance (window , AbstractWindow ):
4252 return window
53+
54+ from vtkmodules .vtkRenderingCore import vtkRenderWindow
55+
4356 if isinstance (window , vtkRenderWindow ):
4457 return VtkWindow (window )
58+
4559 raise RuntimeError (
4660 "Invalid window object provided: expected an instance of AbstractWindow"
4761 )
@@ -73,89 +87,6 @@ def encode(
7387 return self ._impl (np_image , self .value , cols , rows , quality , now_ms )
7488
7589
76- class AbstractWindow (ABC ):
77- """
78- Abstract base class for interacting with a remote window through the RCA.
79-
80- Subclasses must implement the abstract methods defined in this class
81- to enable interaction with the window.
82- """
83-
84- @property
85- @abstractmethod
86- def img_cols_rows (self ) -> tuple [NDArray , int , int ]:
87- """
88- Returns a tuple containing:
89- - the window content as a NumPy array,
90- - the number of columns,
91- - and the number of rows.
92-
93- Called by the scheduler to render the current window view.
94- """
95- pass
96-
97- @abstractmethod
98- def process_resize_event (self , width : int , height : int ) -> None :
99- """
100- Handle a resize event for the RCA (RenderWindowInteractor).
101-
102- This method is triggered by the adapter whenever the window is resized.
103- """
104- pass
105-
106- @abstractmethod
107- def process_interaction_event (self , event : dict ) -> None :
108- """
109- Handle an interaction event from the RCA (RenderWindowInteractor).
110-
111- This method is invoked by the adapter whenever an interaction event occurs.
112- Refer to the event types defined in:
113- https://github.com/Kitware/vtk-js/blob/master/Sources/Rendering/Core/RenderWindowInteractor/index.js
114- """
115- pass
116-
117-
118- class VtkWindow (AbstractWindow ):
119- def __init__ (self , vtk_render_window : vtkRenderWindow ):
120- self ._vtk_render_window = vtk_render_window
121- self ._window_to_image = vtkWindowToImageFilter ()
122- self ._window_to_image .SetInput (vtk_render_window )
123- self ._window_to_image .SetScale (1 )
124- self ._window_to_image .ReadFrontBufferOff ()
125- self ._window_to_image .ShouldRerenderOff ()
126- self ._window_to_image .FixBoundaryOn ()
127- self ._iren = self ._vtk_render_window .GetInteractor ()
128- self ._iren .EnableRenderOff ()
129- self ._vtk_render_window .ShowWindowOff ()
130-
131- @property
132- def img_cols_rows (self ):
133- self ._vtk_render_window .Render ()
134- self ._window_to_image .Modified ()
135- self ._window_to_image .Update ()
136-
137- image_data = self ._window_to_image .GetOutput ()
138- rows , cols , _ = image_data .GetDimensions ()
139- scalars = image_data .GetPointData ().GetScalars ()
140- np_image = vtk_to_numpy (scalars )
141- np_image = np_image .reshape ((cols , rows , - 1 ))
142- np_image [:] = np_image [::- 1 , :, :]
143- return np_image , cols , rows
144-
145- def process_resize_event (self , width , height ):
146- self ._iren .UpdateSize (width , height )
147-
148- if Version (vtkVersion ().vtk_version ) < Version ("9.5" ):
149- self ._iren .InvokeEvent (vtkCommand .WindowResizeEvent )
150-
151- def process_interaction_event (self , event ):
152- event_type = event ["type" ]
153- if event_type in ["StartInteractionEvent" , "EndInteractionEvent" ]:
154- return
155-
156- vtkRemoteInteractionAdapter .ProcessEvent (self ._iren , json .dumps (event ))
157-
158-
15990class RcaRenderScheduler :
16091 """
16192 Render scheduler which renders images and pushing the encoded output to a given callback function.
0 commit comments