3.6 KiB
3.6 KiB
Transformation Flow and Synchronization System
This document describes how transformations are applied and synchronized between the interactive 3D viewport, the visualization puppets, and the underlying mathematical models within the uLib framework.
Architecture Overview
The system follows a Model-View-Controller (MVC) like pattern where:
- Model:
uLib::AffineTransform(or derived classes likeContainerBox). - View/Puppet:
uLib::Vtk::Puppet(and specialized derivations likeVtk::Assembly). - Controller/Interaction:
vtkHandlerWidget(the transformation gizmo).
1. Interaction Flow (Gizmo -> Model)
When a user interacts with the vtkHandlerWidget (dragging arrows, rings, or cubes), the following chain of events occurs:
sequenceDiagram
participant User
participant HW as vtkHandlerWidget
participant VP as vtkViewport
participant P as vtkPuppet
participant M as uLib Model
User->>HW: Drag handle (MouseMove)
HW->>HW: Calculate Delta Matrix (op)
HW->>HW: Total = StartState * op
HW->>HW: Decompose Total into P, O, S
HW->>P: SetPosition, SetOrientation, SetScale
HW-->>VP: Invoke InteractionEvent
VP->>P: SyncFromVtk()
P->>P: Get local matrix from VTK Prop
P->>M: SetMatrix(matrix)
M-->>M: Update local properties (P, O, S)
M-->>P: Emit Updated signal
P->>P: Puppet::Update()
P->>P: (Redundant sanity write to Prop)
Key Principles:
- Single Source of Truth: The
uLib::AffineTransformis the owner of the transformation state. - Internal TRS vs UserMatrix: We apply transformations directly to VTK's internal
Position,Orientation, andScaleproperties. This ensures the data is "visible" to VTK actors and simplifies decomposition. - Cumulative Bias Avoidance: The
HandlerWidgetcalculates transformations relative to the state at the start of the click, preventing numerical drift during a single drag operation.
2. Synchronization Loop Resolution
To prevent infinite loops and "double-transformation" artifacts (especially in assemblies), the following protections are in place:
- Hierarchy Isolation: The
Puppetbase class distinguishes between the Root Property (which receives the puppet's master transformation) and Sub-Parts (which only receive appearance updates like color/visibility). This prevents parts from inheriting the same displacement twice. - Re-entrancy Guards: Puppets use an
m_InUpdateflag to prevent a feedback loop whereSyncFromVtktriggers a Model Update, which then re-triggers the Puppet Update. - Signal Blocking: In specialized cases (like
vtkAssembly),m_BlockUpdateis used to prevent the model-to-puppet push during a puppet-to-model sync.
3. Undo System (Ctrl-Z)
Current Implementation (Delta Chain)
Currently, the system maintains a m_TransformChain of delta matrices.
- Record: After every drag, a delta matrix (
M_{delta} = M_{end} \cdot M_{start}^{-1}) is appended to the chain. - Undo: The last delta is removed, and the prop is reconstructed by reapplying the remaining chain from a
BaseMatrix.
Planned Improvement (TRS Snapshots)
We are migrating to a uLib::TRS snapshot system for Undo.
- Record: At the start of a drag, the current
TRSstate of the object is pushed to them_UndoStack. - Undo: The top
TRSis popped and applied directly to the model.
This approach is more robust because:
- It eliminates matrix multiplication error accumulation.
- It bypasses rotation convention/order issues (Gimbal lock in deltas).
- It returns the object to exactly its previous property values.