74 lines
3.6 KiB
Markdown
74 lines
3.6 KiB
Markdown
# 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 like `ContainerBox`).
|
|
- **View/Puppet**: `uLib::Vtk::Puppet` (and specialized derivations like `Vtk::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:
|
|
|
|
```mermaid
|
|
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::AffineTransform` is the owner of the transformation state.
|
|
- **Internal TRS vs UserMatrix**: We apply transformations directly to VTK's internal `Position`, `Orientation`, and `Scale` properties. This ensures the data is "visible" to VTK actors and simplifies decomposition.
|
|
- **Cumulative Bias Avoidance**: The `HandlerWidget` calculates 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:
|
|
|
|
1. **Hierarchy Isolation**: The `Puppet` base 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.
|
|
2. **Re-entrancy Guards**: Puppets use an `m_InUpdate` flag to prevent a feedback loop where `SyncFromVtk` triggers a Model Update, which then re-triggers the Puppet Update.
|
|
3. **Signal Blocking**: In specialized cases (like `vtkAssembly`), `m_BlockUpdate` is 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 `TRS` state of the object is pushed to the `m_UndoStack`.
|
|
- **Undo**: The top `TRS` is 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.
|