Skip to content

Decompose InteractiveViewer into composed subsystem objects#68

Merged
brendancol merged 1 commit intomasterfrom
feature/phase1-composition
Feb 28, 2026
Merged

Decompose InteractiveViewer into composed subsystem objects#68
brendancol merged 1 commit intomasterfrom
feature/phase1-composition

Conversation

@brendancol
Copy link
Contributor

@brendancol brendancol commented Feb 28, 2026

Summary

  • Breaks the 6500-line InteractiveViewer god class (~150 instance variables) into 10 focused subsystem modules under rtxpy/viewer/, using @property delegation so all existing code paths (ViewerProxy, JupyterViewer, _MeshChunkManager, accessor.py) work unchanged with zero modifications
  • Replaces the ~300-line _handle_key_press if/elif chain with declarative key-binding dispatch tables (SHIFT_BINDINGS, KEY_BINDINGS, SPECIAL_BINDINGS) and 30 thin action methods
  • Cleans up the main loop: moves poll_events() before _tick() (fixes one-frame input lag), extracts _drain_command_queue() and _present_if_dirty()

New subsystem classes

Module Class Responsibility
input_state.py InputState Keyboard/mouse input tracking
camera.py CameraState Position, orientation, FOV, time presets
render_settings.py RenderSettings Shadows, AO, colormap, denoiser, DOF + reset_accumulation()
overlays.py OverlayManager Overlay layers, basemap cycling, tile service
geometry_layers.py GeometryLayerManager Geometry groups, point cloud colors, chunk manager
terrain.py TerrainState Raster data, spacing, elevation stats, mesh caches
observers.py ObserverManager + Observer Multi-observer system, viewshed, drones
wind.py WindState Wind particle simulation + GPU buffers
hud.py HUDState Title, legend, help pages, minimap
keybindings.py (tables) Declarative key-binding dispatch

Implements #61, #62, #63, #64.

Test plan

  • All 291 tests pass (pytest rtxpy/tests/ -x)
  • from rtxpy.engine import InteractiveViewer, explore works
  • from rtxpy import explore works
  • from rtxpy.notebook import JupyterViewer works
  • All 30 action method names in keybinding tables verified against InteractiveViewer
  • Manual smoke test with real DEM (all keyboard shortcuts)

Break the 6500-line god class into 10 focused subsystem modules under
rtxpy/viewer/, using @Property delegation so all existing code paths
(ViewerProxy, JupyterViewer, _MeshChunkManager, accessor.py) work
unchanged.

New subsystem classes:
- InputState: keyboard/mouse input tracking
- CameraState: position, orientation, FOV, time presets
- RenderSettings: shadows, AO, colormap, denoiser, DOF
- OverlayManager: overlay layers, basemap cycling, tile service
- GeometryLayerManager: geometry groups, point cloud colors, chunks
- TerrainState: raster data, spacing, elevation stats, mesh caches
- ObserverManager + Observer: multi-observer system, viewshed, drones
- WindState: wind particle simulation + GPU buffers
- HUDState: title, legend, help pages, minimap

Also:
- Declarative key-binding dispatch tables replace ~300-line if/elif chain
- 30 thin action methods for table-driven dispatch
- reset_accumulation() replaces 10+ inline copies
- Main loop: poll_events() moved before _tick(), extracted
  _drain_command_queue() and _present_if_dirty()

Implements #61, #62, #63, #64.
@brendancol brendancol merged commit 78cb357 into master Feb 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant