Skip to content

VTKLocalView and vtkAxesActor do not work well together #708

Open
@adam-urbanczyk

Description

@adam-urbanczyk

Using VtkLocalView results in a weird behavior of a vtkAxesActor instance:

(1) initial zoom is too high

(2) it actually responds to zooming

(3) With remote view all is fine

Additionally background settings do not seem to work as expected.

To Reproduce

See this PR CadQuery/cadquery#1786

I tried to distill the code somewhat

Code

from asyncio import (
    new_event_loop,
    set_event_loop,
    run_coroutine_threadsafe,
    AbstractEventLoop,
)
from typing import Optional
from threading import Thread
from itertools import chain
from webbrowser import open_new_tab

from trame.app import get_server, Server
from trame.widgets import html, vtk as vtk_widgets, client
from trame.ui.html import DivLayout

from vtkmodules.vtkRenderingCore import (
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkProp3D,
    vtkActor,
)

from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera

FULL_SCREEN = "position:absolute; left:0; top:0; width:100vw; height:100vh;"


class Figure:

    server: Server
    win: vtkRenderWindow
    ren: vtkRenderer
    view: vtk_widgets.VtkRemoteView
    actors: list[vtkProp3D]
    loop: AbstractEventLoop
    thread: Thread
    empty: bool
    
    _instance = None
    _initialized: bool = False

    def __new__(cls, *args, **kwargs):

        if not cls._instance:
            cls._instance = object.__new__(cls)

        return cls._instance

    def __init__(self, port: int = 18081):

        if self._initialized:
            return

        self.loop = new_event_loop()
        set_event_loop(self.loop)

        # vtk boilerplate
        renderer = vtkRenderer()
        win = vtkRenderWindow()
        w, h = win.GetScreenSize()
        win.SetSize(w, h)
        win.AddRenderer(renderer)
        win.OffScreenRenderingOn()

        inter = vtkRenderWindowInteractor()
        inter.SetInteractorStyle(vtkInteractorStyleTrackballCamera())
        inter.SetRenderWindow(win)

        # background
        renderer.SetBackground(1, 1, 1)
        renderer.GradientBackgroundOn()

        # axes
        axes = vtkAxesActor()
        axes.SetDragable(0)

        orient_widget = vtkOrientationMarkerWidget()

        orient_widget.SetOrientationMarker(axes)
        orient_widget.SetViewport(0.9, 0.0, 1.0, 0.2)
        orient_widget.SetZoom(1.1)
        orient_widget.SetInteractor(inter)
        orient_widget.SetCurrentRenderer(renderer)
        orient_widget.EnabledOn()
        orient_widget.InteractiveOff()

        self.axes = axes
        self.orient_widget = orient_widget
        self.win = win
        self.ren = renderer

        self.shapes = {}
        self.actors = []

        # server
        server = get_server("CQ-server")
        server.client_type = "vue3"

        # layout
        with DivLayout(server):
            client.Style("body { margin: 0; }")

            with html.Div(style=FULL_SCREEN):
                self.view = vtk_widgets.VtkLocalView(
                    win, interactive_ratio=1, interactive_quality=100
                )

        server.state.flush()

        self.server = server
        self.loop = new_event_loop()

        def _run_loop():
            set_event_loop(self.loop)
            self.loop.run_forever()

        self.thread = Thread(target=_run_loop, daemon=True)
        self.thread.start()

        coro = server.start(
            thread=True,
            exec_mode="coroutine",
            port=port,
            open_browser=False,
            show_connection_info=False,
        )

        if coro:
            self._run(coro)

        # prevent reinitialization
        self._initialized = True

        # view is initialized as empty
        self.empty = True
        self.last = None

        # open webbrowser
        open_new_tab(f"http://localhost:{port}")

    def _run(self, coro):

        run_coroutine_threadsafe(coro, self.loop)


fig = Figure()

Expected behavior

Remote and local view should be aligned wrt axes handling.

Screenshots

Image
Image

Platform:

Device:

  • Desktop
  • Mobile

OS:

  • Windows
  • MacOS
  • Linux
  • Android
  • iOS

Browsers Affected:

  • Chrome
  • Firefox
  • Microsoft Edge
  • Safari
  • Opera
  • Brave
  • IE 11

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions