Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions examples/01_vtk/vtk_cone_simple_touch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import vtkmodules.vtkRenderingOpenGL2 # noqa
from vtkmodules.vtkFiltersSources import vtkConeSource

# Required for interactor initialization
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
)

from trame.app import TrameApp
from trame.app.testing import enable_testing
from trame.decorators import change
from trame.ui.vuetify3 import SinglePageLayout
from trame.widgets import vuetify3 as v3

# use this import path to allow -e install for dev
from trame_rca.widgets import rca

v3.enable_lab()

DEFAULT_RESOLUTION = 6


class ConeApp(TrameApp):
def __init__(self, server=None):
super().__init__(server)

self.server.cli.add_argument("--encoder", default="turbo-jpeg") # jpeg
args, _ = self.server.cli.parse_known_args()
self.state.encoder = args.encoder
self.render_window, self.renderer, self.cone_source = self.setup_vtk()
self.build_ui()

def setup_vtk(self):
renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)

renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.GetInteractorStyle().SetCurrentStyleToMultiTouchCamera()

cone_source = vtkConeSource()
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(cone_source.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)

renderer.AddActor(actor)
renderer.ResetCamera()

return renderWindow, renderer, cone_source

def build_ui(self):
with SinglePageLayout(self.server, full_height=True) as self.ui:
self.ui.title.set_text("RCA rendering")

with self.ui.toolbar:
v3.VSpacer()
v3.VSlider(
v_model=("resolution", DEFAULT_RESOLUTION),
min=3,
max=60,
step=1,
hide_details=True,
density="compact",
style="max-width: 300px",
)

v3.VBtn(icon="mdi-undo-variant", click=self.update_reset_resolution)

with self.ui.content:
with v3.VContainer(
fluid=True,
classes="pa-0 fill-height position-relative",
):
view = rca.RemoteControlledArea(display="image")
self.view_handler = view.create_view_handler(
self.render_window,
encoder=self.state.encoder,
)

self.ui.icon.click = self.reset_camera

@change("resolution")
def update_cone(self, resolution, **kwargs):
self.cone_source.SetResolution(resolution)
self.view_handler.update()

def update_reset_resolution(self):
self.state.resolution = DEFAULT_RESOLUTION

def reset_camera(self):
# FIXME may need to reset center of roll/zoom/...
self.renderer.ResetCamera()
self.view_handler.update()


# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":
app = ConeApp()
enable_testing(app.server)
app.server.start()
39 changes: 30 additions & 9 deletions vue-components/src/utils/interactorStyle.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,23 +199,29 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {

publicAPI.handleStartPinch = (callData) => {
publicAPI.startDolly();
const { scale } = callData;
const { scale: factor, touches: positions } = callData;
// model._interactor.requestAnimation(publicAPI.handleStartPinch);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
publicAPI.invokeRemoteGestureEvent({
type: 'StartPinch',
scale,
factor,
positions,
...model.remoteEventAddOn,
});
};

//----------------------------------------------------------------------------

let lastPinchEvent = {};
publicAPI.handlePinch = (callData) => {
const { scale } = callData;
const { scale: factor, touches: positions } = callData;
lastPinchEvent = {
factor,
positions,
};
publicAPI.invokeRemoteGestureEvent({
type: 'Pinch',
scale,
factor,
positions,
...model.remoteEventAddOn,
});
};
Expand All @@ -226,6 +232,7 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {
publicAPI.endDolly();
publicAPI.invokeRemoteGestureEvent({
type: 'EndPinch',
...lastPinchEvent,
...model.remoteEventAddOn,
});
// model._interactor.cancelAnimation(publicAPI.handleStartPinch);
Expand All @@ -236,23 +243,29 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {

publicAPI.handleStartRotate = (callData) => {
publicAPI.startRotate();
const { rotation } = callData;
const { rotation, touches: positions } = callData;
// model._interactor.requestAnimation(publicAPI.handleStartRotate);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
publicAPI.invokeRemoteGestureEvent({
type: 'StartRotate',
rotation,
positions,
...model.remoteEventAddOn,
});
};

//----------------------------------------------------------------------------

publicAPI.handleRotate = (callData) => {
const { rotation } = callData;
const { rotation, touches: positions } = callData;
model.lastRotateEvent = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not let lastRotateEvent outside of this function ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

rotation,
positions,
};
publicAPI.invokeRemoteGestureEvent({
type: 'Rotate',
rotation,
positions,
...model.remoteEventAddOn,
});
};
Expand All @@ -263,6 +276,7 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {
publicAPI.endRotate();
publicAPI.invokeRemoteGestureEvent({
type: 'EndRotate',
...model.lastRotateEvent,
...model.remoteEventAddOn,
});
// model._interactor.cancelAnimation(publicAPI.handleStartRotate);
Expand All @@ -273,23 +287,29 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {

publicAPI.handleStartPan = (callData) => {
publicAPI.startPan();
const { translation } = callData;
const { translation, touches: positions } = callData;
// model._interactor.requestAnimation(publicAPI.handleStartPan);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
publicAPI.invokeRemoteGestureEvent({
type: 'StartPan',
translation,
positions,
...model.remoteEventAddOn,
});
};

//----------------------------------------------------------------------------

publicAPI.handlePan = (callData) => {
const { translation } = callData;
const { translation, touches: positions } = callData;
model.lastPanEvent = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not let lastPanEvent outside of handlePan ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that is true, that could be fixed as well.

translation,
positions,
};
publicAPI.invokeRemoteGestureEvent({
type: 'Pan',
translation,
positions,
...model.remoteEventAddOn,
});
};
Expand All @@ -300,6 +320,7 @@ function vtkInteractorStyleRemoteMouse(publicAPI, model) {
publicAPI.endPan();
publicAPI.invokeRemoteGestureEvent({
type: 'EndPan',
...model.lastPanEvent,
...model.remoteEventAddOn,
});
// model._interactor.cancelAnimation(publicAPI.handleStartPan);
Expand Down
Loading