Skip to content

feat(view): add turntable mode to interactive viewer #371

Description

@pfmephisto

Problem

The interactive rux view viewer uses VTK's default trackball camera, which makes it hard to present or record a scene. There is no way to continuously orbit the scene at a steady pace, which is useful for reviewing geometry or capturing footage.

Goal

Add a turntable mode that:

  • Rotates the camera continuously around the scene's vertical axis (world Z)
  • Keeps the focal point fixed at the scene centre
  • Can be toggled on/off and paused with keyboard shortcuts

Implementation context

Current viewer architecture

The viewer is built on pcl::visualization::PCLVisualizer, which wraps VTK's vtkInteractorStyleTrackballCamera. The main loop runs in apps/rux/src/processing_observer.cpp:671 via viewer->spinOnce(100ms). No custom interactor style exists today.

Camera manipulation uses the VTK API directly — see apps/rux/src/view/panorama_handler.cpp:135–146 for a working example:

cam->SetPosition(x, y, z);
cam->SetFocalPoint(cx, cy, cz);
cam->SetViewUp(0, 0, 1);

Orbit math (reference)

libs/reusex/src/visualize/render_view.cpp:612–625 already implements a circular orbit:

const double azimuth = 2.0 * pi * orbit_index / orbit_count;
const double elevation = elevation_deg * pi / 180.0;
cam->SetPosition(
    center[0] + reach * cos(azimuth) * cos(elevation),
    center[1] + reach * sin(azimuth) * cos(elevation),
    center[2] + reach * sin(elevation));
cam->SetViewUp(0.0, 0.0, 1.0);

For turntable mode the same formula is used with elevation fixed (e.g. 20°) and azimuth incrementing each frame.

State pattern

Follow the PanoramaState pattern (apps/rux/include/view/panorama_handler.hpp:24–35) — a small struct held by shared_ptr and shared with callbacks:

struct TurntableState {
    bool active = false;
    bool spinning = true;
    double azimuth = 0.0;            // radians
    double angular_velocity = 0.3;   // rad/s
    double radius = 5.0;
    double elevation_deg = 20.0;
    std::array<double,3> center = {0,0,0};
};

Compute center and radius from the scene bounding box on activation (see render_view.cpp:580–582 for the bbox query pattern).

Integration points

  1. State + keyboard callback — add to apps/rux/src/view.cpp after the pano_state block (around line 130). Register keys via viewer->registerKeyboardCallback(...) — see the Escape key handler at lines 220–238 for the pattern.

    Suggested keys: t = toggle on/off, Space = pause/resume spin, [/] = decrease/increase speed.

  2. Per-frame update — enqueue a camera update task each tick. The task queue is drained every 100 ms in processing_observer.cpp:671. Use observer.viewer_enqueue_task(...) (same pattern as other renderers).

  3. Help text — add turntable controls to the help overlay following the pattern in apps/rux/src/view/component_renderer.cpp:106–145.

  4. No interactor changes needed — when turntable is active, manually calling SetPosition/SetFocalPoint each frame overrides VTK's trackball. When it is off, normal mouse interaction resumes automatically.

Acceptance criteria

  • t toggles turntable mode; viewer prints a brief status message
  • Space pauses/resumes spinning while in turntable mode
  • [ / ] decrease/increase angular speed
  • Camera stays locked to world-Z up; scene centre auto-detected from loaded geometry
  • Normal trackball interaction works when turntable is off

Key files

File Lines Purpose
apps/rux/src/processing_observer.cpp 645–676 Viewer init and main spin loop
apps/rux/src/view.cpp 105–319 Callback registration, pano_state pattern to follow
apps/rux/src/view/panorama_handler.cpp 135–146 Camera SetPosition/FocalPoint/ViewUp example
apps/rux/include/view/panorama_handler.hpp 24–35 State struct pattern
libs/reusex/src/visualize/render_view.cpp 612–625 Orbit math to adapt
apps/rux/src/view/component_renderer.cpp 106–145 Help text addition point
apps/rux/include/view/label_renderer.hpp 77–173 Keyboard callback template pattern

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions