Domain Visualizer
The pilot’s domain viewer (RDomainWidget) shows 2D and
3D unstructured-mesh domains and fields, rendered through Qt’s
QRhi. It is hosted as a sub-window in the
pilot and is fully controllable from Python: populate the scene, navigate the
camera, toggle layers, and capture frames from code the same way the mouse
drives them.
Showing a domain
Mesh wireframe: updateMesh(mesh) draws the unstructured mesh (2D faces
or 3D cells) as a wireframe; showMesh(on) toggles it.
Colored field: updateColorField(vertices, colors, indices) draws
per-vertex-colored triangles over the domain. The field is swappable at
runtime: call it again to replace the previous one.
Boundary highlight: showBoundary(ibc, on) highlights boundary set
ibc.
Orientation guide: showAxis(on) shows a small axis triad in the corner,
two axes for a 2D domain and three for a 3D one, oriented by the camera. It
is hidden by default.
Camera navigation
The viewer has one camera with three modes; each suits a different domain.
Choose the mode from the View > Camera menu, or set cameraMode from
Python.
Orbit is the default. It is a turntable orbit: the up axis stays fixed, so
the horizon never rolls and a hard pitch past vertical eases off instead of
flipping the view. Loading a 2D domain switches to pan/zoom automatically,
because the orthographic projection a 2D domain uses ignores the orbit dolly
and wants the in-plane wheel zoom instead.
Mouse, wheel, and pinch
Left-drag rotates: orbit the center in orbit mode, look around in
first-person mode, or pan in 2D pan/zoom mode.
Middle- or right-drag pans in any mode.
Wheel zooms; what it does depends on the mode (see the table above).
Pinch on a trackpad or touchscreen zooms in any mode.
Keyboard
W / A / S / D or the arrow keys move the camera: forward and back,
and strafe left and right.
Esc reframes the whole domain (fit to scene).
The View > Camera move submenu offers the same nudges as clickable actions,
plus fixed-step yaw and pitch rotation and a reset.
From Python
The camera exposes the same primitives the mouse and wheel drive, so a domain
navigates identically from code:
from solvcon import pilot
mgr = pilot.RManager.instance.setUp()
viewer = mgr.add3DWidget()
viewer.updateMesh(mesh) # show the wireframe
viewer.cameraMode = "orbit" # orbit a 3D domain (the default)
viewer.fitCameraToScene() # frame the whole domain
viewer.rotateCamera(40.0, 15.0) # orbit by a pixel delta
viewer.panCamera(20.0, 0.0) # pan by a pixel delta
viewer.zoomCamera(3.0) # zoom by wheel notches
viewer.pinchCamera(1.5) # zoom by a pinch factor (>1 zooms in)
The pose is readable and settable directly as (x, y, z) tuples through
cameraPosition, cameraTarget, and cameraUp, so a view can be saved and
restored, or set to an exact framing.
Capturing frames
Both grab the frame deterministically inside the Qt event loop, which is what
the pytest screenshot tests rely on.