fixed most ( still units error )
This commit is contained in:
73
docs/transformation_system.md
Normal file
73
docs/transformation_system.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 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.
|
||||
@@ -56,6 +56,67 @@
|
||||
|
||||
namespace uLib {
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////// TRS PARAMETERS /////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef Eigen::Affine3f AffineMatrix;
|
||||
|
||||
class TRS {
|
||||
public:
|
||||
Vector3f position = Vector3f::Zero();
|
||||
Vector3f rotation = Vector3f::Zero();
|
||||
Vector3f scaling = Vector3f::Ones();
|
||||
|
||||
TRS() = default;
|
||||
|
||||
TRS(const class AffineTransform& at);
|
||||
|
||||
TRS(const Matrix4f& mat) {
|
||||
this->FromMatrix(mat);
|
||||
}
|
||||
|
||||
void FromMatrix(const Matrix4f& mat) {
|
||||
this->position = mat.block<3,1>(0,3);
|
||||
|
||||
Matrix3f linear = mat.block<3,3>(0,0);
|
||||
this->scaling(0) = linear.col(0).norm();
|
||||
this->scaling(1) = linear.col(1).norm();
|
||||
this->scaling(2) = linear.col(2).norm();
|
||||
|
||||
Matrix3f rot = linear;
|
||||
if (this->scaling(0) > 1e-6) rot.col(0) /= this->scaling(0);
|
||||
if (this->scaling(1) > 1e-6) rot.col(1) /= this->scaling(1);
|
||||
if (this->scaling(2) > 1e-6) rot.col(2) /= this->scaling(2);
|
||||
|
||||
// Decompose to Euler angles matching VTK (M = Rz * Ry * Rx)
|
||||
// Store internally as RADIANS (standard for uLib properties)
|
||||
Vector3f euler = rot.eulerAngles(2, 1, 0);
|
||||
this->rotation = Vector3f(euler(2), euler(1), euler(0));
|
||||
}
|
||||
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & HRPU(position, "mm");
|
||||
ar & HRPU(rotation, "deg"); // Metadata informs UI to convert to/from degrees
|
||||
ar & HRP(scaling);
|
||||
}
|
||||
|
||||
AffineMatrix GetAffineMatrix() const {
|
||||
AffineMatrix t = AffineMatrix::Identity();
|
||||
t.translate(position);
|
||||
|
||||
// rotation is in Radians here
|
||||
t.rotate(Eigen::AngleAxisf(rotation.z(), Vector3f::UnitZ()));
|
||||
t.rotate(Eigen::AngleAxisf(rotation.y(), Vector3f::UnitY()));
|
||||
t.rotate(Eigen::AngleAxisf(rotation.x(), Vector3f::UnitX()));
|
||||
|
||||
t.scale(scaling);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////// AFFINE TRANSFORM WRAPPER //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -64,21 +125,15 @@ class AffineTransform : virtual public Object {
|
||||
public:
|
||||
uLibTypeMacro(AffineTransform, Object)
|
||||
|
||||
/**
|
||||
* @brief Grouped transformation parameters for property-based control.
|
||||
*/
|
||||
struct {
|
||||
Vector3f Position = Vector3f::Zero();
|
||||
Vector3f Orientation = Vector3f::Zero();
|
||||
Vector3f Scale = Vector3f::Ones();
|
||||
TRS Transform;
|
||||
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & HRPU(Position, "mm");
|
||||
ar & HRPU(Orientation, "deg");
|
||||
ar & HRP(Scale);
|
||||
}
|
||||
} Transform;
|
||||
private:
|
||||
void NotifyProperties() {
|
||||
PropertyBase *p;
|
||||
if ((p = this->GetProperty("Transform.position"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.rotation"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.scaling"))) p->Updated();
|
||||
}
|
||||
|
||||
protected:
|
||||
Eigen::Affine3f m_T;
|
||||
@@ -140,11 +195,25 @@ public:
|
||||
}
|
||||
|
||||
void SetPosition(const Vector3f v) {
|
||||
this->Transform.Position = v;
|
||||
this->Sync();
|
||||
this->Transform.position = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetPosition() const { return this->Transform.position; }
|
||||
|
||||
Vector3f GetPosition() const { return this->Transform.Position; }
|
||||
void SetOrientation(const Vector3f v) {
|
||||
this->Transform.rotation = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetOrientation() const { return this->Transform.rotation; }
|
||||
|
||||
void SetScale(const Vector3f v) {
|
||||
this->Transform.scaling = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetScale() const { return this->Transform.scaling; }
|
||||
|
||||
void SetRotation(const Matrix3f m) {
|
||||
this->m_T.linear() = m;
|
||||
@@ -154,24 +223,15 @@ public:
|
||||
Matrix3f GetRotation() const { return this->m_T.rotation(); }
|
||||
|
||||
void Translate(const Vector3f v) {
|
||||
this->Transform.Position += v;
|
||||
this->Transform.position += v;
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
void Scale(const Vector3f v) {
|
||||
this->Transform.Scale = this->Transform.Scale.cwiseProduct(v);
|
||||
this->Transform.scaling = this->Transform.scaling.cwiseProduct(v);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
Vector3f GetScale() const { return this->Transform.Scale; }
|
||||
|
||||
void SetOrientation(const Vector3f v) {
|
||||
this->Transform.Orientation = v;
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
Vector3f GetOrientation() const { return this->Transform.Orientation; }
|
||||
|
||||
|
||||
void Rotate(const Matrix3f m) {
|
||||
this->m_T.rotate(m);
|
||||
@@ -197,7 +257,7 @@ public:
|
||||
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); this->UpdatePropertiesFromMatrix(); }
|
||||
|
||||
void EulerYZYRotate(const Vector3f e) {
|
||||
this->Transform.Orientation = e;
|
||||
this->Transform.rotation = e;
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
@@ -213,30 +273,12 @@ public:
|
||||
* @brief Decomposes the internal matrix m_T back into Position, Orientation, and Scale properties.
|
||||
*/
|
||||
void UpdatePropertiesFromMatrix() {
|
||||
// 1. Position
|
||||
Transform.Position = m_T.translation();
|
||||
this->Transform.FromMatrix(this->GetMatrix());
|
||||
|
||||
// 2. Scale
|
||||
Matrix3f linear = m_T.linear();
|
||||
Transform.Scale(0) = linear.col(0).norm();
|
||||
Transform.Scale(1) = linear.col(1).norm();
|
||||
Transform.Scale(2) = linear.col(2).norm();
|
||||
|
||||
// 3. Rotation (Normalization removes scale)
|
||||
Matrix3f rotation = linear;
|
||||
if (Transform.Scale(0) > 1e-6) rotation.col(0) /= Transform.Scale(0);
|
||||
if (Transform.Scale(1) > 1e-6) rotation.col(1) /= Transform.Scale(1);
|
||||
if (Transform.Scale(2) > 1e-6) rotation.col(2) /= Transform.Scale(2);
|
||||
|
||||
// Euler YZY (indices 1, 2, 1)
|
||||
Vector3f euler = rotation.eulerAngles(1, 2, 1);
|
||||
Transform.Orientation = euler / CLHEP::degree;
|
||||
|
||||
// Notify properties
|
||||
PropertyBase* p;
|
||||
if ((p = this->GetProperty("Transform.Position"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.Orientation"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.Scale"))) p->Updated();
|
||||
PropertyBase *p;
|
||||
if ((p = this->GetProperty("Transform.position"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.rotation"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.scaling"))) p->Updated();
|
||||
}
|
||||
|
||||
signals:
|
||||
@@ -247,22 +289,19 @@ signals:
|
||||
}
|
||||
|
||||
private:
|
||||
/** Synchronizes m_T with properties */
|
||||
void Sync() {
|
||||
m_T = Eigen::Affine3f::Identity();
|
||||
m_T.translate(Transform.Position);
|
||||
|
||||
// Orientation (using YZY order as implied by EulerYZYRotate)
|
||||
Matrix3f mat;
|
||||
mat = Eigen::AngleAxisf(Transform.Orientation.x() * CLHEP::degree, Vector3f::UnitY())
|
||||
* Eigen::AngleAxisf(Transform.Orientation.y() * CLHEP::degree, Vector3f::UnitZ())
|
||||
* Eigen::AngleAxisf(Transform.Orientation.z() * CLHEP::degree, Vector3f::UnitY());
|
||||
m_T.rotate(mat);
|
||||
|
||||
m_T.scale(Transform.Scale);
|
||||
}
|
||||
void Sync() {
|
||||
m_T.matrix() = this->Transform.GetAffineMatrix().matrix();
|
||||
}
|
||||
};
|
||||
|
||||
inline TRS::TRS(const AffineTransform& at) {
|
||||
this->position = at.GetPosition();
|
||||
this->rotation = at.GetOrientation();
|
||||
this->scaling = at.GetScale();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ set(HEADERS uLibVtkInterface.h
|
||||
vtkHandlerWidget.h
|
||||
vtkQViewport.h
|
||||
vtkViewport.h
|
||||
vtkPolydata.h
|
||||
vtkObjectsContext.h
|
||||
)
|
||||
|
||||
@@ -12,7 +11,6 @@ set(SOURCES uLibVtkInterface.cxx
|
||||
vtkHandlerWidget.cpp
|
||||
vtkQViewport.cpp
|
||||
vtkViewport.cpp
|
||||
vtkPolydata.cpp
|
||||
vtkObjectsContext.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
#include "HEP/Detectors/MuonEvent.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
#include "HEP/Detectors/MuonScatter.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
|
||||
class vtkRenderWindowInteractor;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "HEP/Geant/GeantEvent.h"
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
#include <vtkActor.h>
|
||||
|
||||
namespace uLib {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "HEP/Geant/Solid.h"
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
|
||||
class vtkActor;
|
||||
|
||||
|
||||
@@ -25,27 +25,11 @@
|
||||
|
||||
|
||||
|
||||
#ifndef U_VTKULIBPROP_H
|
||||
#define U_VTKULIBPROP_H
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
class vtkProp;
|
||||
|
||||
namespace uLib {
|
||||
namespace Abstract {
|
||||
|
||||
class uLibVtkProp {
|
||||
public:
|
||||
virtual vtkProp *GetProp() = 0;
|
||||
|
||||
protected:
|
||||
~uLibVtkProp() {}
|
||||
};
|
||||
#include <Vtk/vtkMuonContainerScattering.h>
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // VTKULIBPROP_H
|
||||
// TO BE CONTINUED //
|
||||
74
src/Vtk/HEP/MuonTomography/vtkMuonContainerScattering.h
Normal file
74
src/Vtk/HEP/MuonTomography/vtkMuonContainerScattering.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*//////////////////////////////////////////////////////////////////////////////
|
||||
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||
All rights reserved
|
||||
|
||||
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||
|
||||
------------------------------------------------------------------
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
|
||||
#ifndef VTKMUONCONTAINERSCATTERING_H
|
||||
#define VTKMUONCONTAINERSCATTERING_H
|
||||
|
||||
|
||||
|
||||
#include "Math/Dense.h"
|
||||
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "Detectors/MuonScatter.h"
|
||||
|
||||
class vtkRenderWindowInteractor;
|
||||
|
||||
namespace uLib {
|
||||
|
||||
class vtkMuonContainerScattering : public Abstract::uLibVtkPolydata {
|
||||
typedef MuonScatter Content;
|
||||
public:
|
||||
vtkMuonContainerScattering(const MuonScatter &content);
|
||||
~vtkMuonScatter();
|
||||
|
||||
Content& GetContent();
|
||||
|
||||
void PrintSelf(std::ostream &o) const;
|
||||
|
||||
virtual vtkProp *GetProp();
|
||||
|
||||
virtual vtkPolyData* GetPolyData() const;
|
||||
|
||||
void AddPocaPoint(HPoint3f poca);
|
||||
|
||||
HPoint3f GetPocaPoint();
|
||||
|
||||
void vtkStartInteractive();
|
||||
|
||||
protected:
|
||||
void ConnectInteractor(vtkRenderWindowInteractor *interactor);
|
||||
|
||||
private:
|
||||
void InstallPipe();
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // VTKMUONCONTAINERSCATTERING_H
|
||||
@@ -11,6 +11,7 @@ set(MATH_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkAssembly.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkPolydata.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
set(MATH_HEADERS
|
||||
@@ -22,6 +23,7 @@ set(MATH_HEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkAssembly.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkPolydata.h
|
||||
PARENT_SCOPE)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
@@ -92,13 +92,12 @@ void Assembly::InstallPipe() {
|
||||
void Assembly::contentUpdate() {
|
||||
if (m_InUpdate) return;
|
||||
m_InUpdate = true;
|
||||
|
||||
m_BlockUpdate = false;
|
||||
this->UpdateTransform();
|
||||
this->UpdateBoundingBox();
|
||||
if (m_ChildContext)
|
||||
m_ChildContext->Update();
|
||||
|
||||
m_BlockUpdate = true;
|
||||
Puppet::Update();
|
||||
m_InUpdate = false;
|
||||
}
|
||||
@@ -106,25 +105,29 @@ void Assembly::contentUpdate() {
|
||||
// ------------------------------------------------------------------ //
|
||||
void Assembly::Update() {
|
||||
if (m_InUpdate) return;
|
||||
if (!m_Content || !m_VtkAsm) return;
|
||||
m_InUpdate = true;
|
||||
this->contentUpdate();
|
||||
m_InUpdate = false;
|
||||
}
|
||||
|
||||
if (m_BlockUpdate) {
|
||||
m_BlockUpdate = false;
|
||||
return;
|
||||
}
|
||||
void Assembly::SyncFromVtk() {
|
||||
if (m_InUpdate) return;
|
||||
if (!m_Content || !m_VtkAsm) return;
|
||||
|
||||
m_InUpdate = true;
|
||||
|
||||
// Pull VTK transform back into the uLib model
|
||||
vtkMatrix4x4* vmat = m_VtkAsm->GetUserMatrix();
|
||||
if (vmat) {
|
||||
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||
m_Content->SetMatrix(transform);
|
||||
}
|
||||
double pos[3], ori[3], scale[3];
|
||||
m_VtkAsm->GetPosition(pos);
|
||||
m_VtkAsm->GetOrientation(ori);
|
||||
m_VtkAsm->GetScale(scale);
|
||||
|
||||
m_Content->SetPosition(Vector3f(pos[0], pos[1], pos[2]));
|
||||
m_Content->SetOrientation(Vector3f(ori[0], ori[1], ori[2]) * CLHEP::degree);
|
||||
m_Content->SetScale(Vector3f(scale[0], scale[1], scale[2]));
|
||||
|
||||
this->UpdateBoundingBox();
|
||||
if (m_ChildContext)
|
||||
m_ChildContext->Update();
|
||||
m_ChildContext->SyncFromVtk();
|
||||
|
||||
m_Content->Updated(); // Notify change in model
|
||||
|
||||
@@ -135,10 +138,7 @@ void Assembly::Update() {
|
||||
void Assembly::UpdateTransform() {
|
||||
if (!m_Content || !m_VtkAsm) return;
|
||||
|
||||
Matrix4f mat = m_Content->GetMatrix();
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
Matrix4fToVtk(mat, vmat);
|
||||
m_VtkAsm->SetUserMatrix(vmat);
|
||||
this->ApplyTransform(m_VtkAsm);
|
||||
m_VtkAsm->Modified();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ public:
|
||||
/** @brief Updates the VTK representation from the model (model→VTK). */
|
||||
virtual void Update() override;
|
||||
|
||||
/** @brief Synchronizes the model from the VTK representation (VTK→model). */
|
||||
virtual void SyncFromVtk() override;
|
||||
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||
|
||||
/** @brief Called when the model signals an update (model→VTK push). */
|
||||
|
||||
@@ -80,54 +80,38 @@ void vtkContainerBox::contentUpdate() {
|
||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (!root) return;
|
||||
|
||||
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
||||
if (!vmat) {
|
||||
// Should have been set in InstallPipe, but let's be safe
|
||||
vtkNew<vtkMatrix4x4> mat;
|
||||
root->SetUserMatrix(mat);
|
||||
vmat = mat;
|
||||
}
|
||||
|
||||
d->m_Cube->SetUserMatrix(nullptr);
|
||||
d->m_Axes->SetUserMatrix(nullptr);
|
||||
|
||||
Matrix4f transform = m_Content->GetMatrix();
|
||||
Matrix4fToVtk(transform, vmat);
|
||||
TRS trs(*m_Content);
|
||||
this->ApplyTransform(root);
|
||||
|
||||
root->Modified();
|
||||
m_BlockUpdate = true;
|
||||
m_BlockUpdate = false;
|
||||
Puppet::Update();
|
||||
}
|
||||
|
||||
|
||||
void vtkContainerBox::Update() {
|
||||
this->contentUpdate();
|
||||
}
|
||||
|
||||
void vtkContainerBox::SyncFromVtk() {
|
||||
RecursiveMutex::ScopedLock lock(this->m_UpdateMutex);
|
||||
if (!m_Content) return;
|
||||
|
||||
if (m_BlockUpdate) {
|
||||
m_BlockUpdate = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Use Targeted Blocking: only block the feedback connection to this puppet
|
||||
// boost::signals2::shared_connection_block block(m_Connection);
|
||||
|
||||
vtkProp3D* assembly = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (!assembly) return;
|
||||
|
||||
vtkMatrix4x4* vmat = assembly->GetUserMatrix();
|
||||
if (!vmat) return;
|
||||
double pos[3], ori[3], scale[3];
|
||||
assembly->GetPosition(pos);
|
||||
assembly->GetOrientation(ori);
|
||||
assembly->GetScale(scale);
|
||||
|
||||
m_Content->SetPosition(Vector3f(pos[0], pos[1], pos[2]));
|
||||
m_Content->SetOrientation(Vector3f(ori[0], ori[1], ori[2]) * CLHEP::degree);
|
||||
m_Content->SetScale(Vector3f(scale[0], scale[1], scale[2]));
|
||||
|
||||
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||
|
||||
// Update uLib model's affine transform
|
||||
// if (m_Content->GetParent()) {
|
||||
// Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform;
|
||||
// m_Content->SetMatrix(localT);
|
||||
// } else {
|
||||
m_Content->SetMatrix(transform);
|
||||
// }
|
||||
|
||||
m_Content->Updated(); // Notify change
|
||||
}
|
||||
|
||||
@@ -175,9 +159,11 @@ void vtkContainerBox::InstallPipe() {
|
||||
|
||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (root) {
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
Matrix4fToVtk(c->GetMatrix(), vmat);
|
||||
root->SetUserMatrix(vmat);
|
||||
TRS trs(*c);
|
||||
root->SetPosition(trs.position.x(), trs.position.y(), trs.position.z());
|
||||
root->SetOrientation(trs.rotation.x(), trs.rotation.y(), trs.rotation.z());
|
||||
root->SetScale(trs.scaling.x(), trs.scaling.y(), trs.scaling.z());
|
||||
root->SetUserMatrix(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ public:
|
||||
|
||||
virtual void contentUpdate();
|
||||
|
||||
virtual void Update();
|
||||
virtual void Update() override;
|
||||
virtual void SyncFromVtk() override;
|
||||
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "Math/QuadMesh.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
|
||||
class vtkPolyData;
|
||||
class vtkActor;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "Math/TriangleMesh.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/vtkPolydata.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
|
||||
class vtkPolyData;
|
||||
class vtkActor;
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "vtkHandlerWidget.h"
|
||||
#include "Math/Dense.h"
|
||||
#include "Vtk/Math/vtkDense.h"
|
||||
#include "Core/Property.h"
|
||||
|
||||
|
||||
@@ -75,12 +76,6 @@ namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PUPPET //
|
||||
|
||||
// PIMPL -------------------------------------------------------------------- //
|
||||
|
||||
class PuppetData {
|
||||
@@ -98,9 +93,6 @@ public:
|
||||
m_Dragable(true)
|
||||
{
|
||||
m_Color[0] = m_Color[1] = m_Color[2] = -1.0;
|
||||
m_Position = Vector3d::Zero();
|
||||
m_Orientation = Vector3d::Zero();
|
||||
m_Scale = Vector3d::Ones();
|
||||
}
|
||||
|
||||
~PuppetData() {
|
||||
@@ -126,9 +118,7 @@ public:
|
||||
bool m_Selected;
|
||||
bool m_Visibility;
|
||||
bool m_Dragable;
|
||||
Vector3d m_Position;
|
||||
Vector3d m_Orientation;
|
||||
Vector3d m_Scale;
|
||||
TRS m_Transform;
|
||||
|
||||
void ApplyAppearance(vtkProp *p) {
|
||||
p->SetVisibility(m_Visibility);
|
||||
@@ -154,13 +144,19 @@ public:
|
||||
actor->GetProperty()->SetOpacity(m_Opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle transformation if it's a Prop3D
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(p)) {
|
||||
// NOTE: Usually managed by Puppet::Update from model, but here for direct prop manipulation
|
||||
// p3d->SetPosition(m_Position.data());
|
||||
// p3d->SetOrientation(m_Orientation.data());
|
||||
// p3d->SetScale(m_Scale.data());
|
||||
void ApplyTransform(vtkProp3D* p3d) {
|
||||
if (p3d) {
|
||||
p3d->SetPosition(m_Transform.position.x(), m_Transform.position.y(), m_Transform.position.z());
|
||||
|
||||
// Convert Model Radians to VTK Degrees
|
||||
p3d->SetOrientation(m_Transform.rotation.x() / CLHEP::degree,
|
||||
m_Transform.rotation.y() / CLHEP::degree,
|
||||
m_Transform.rotation.z() / CLHEP::degree);
|
||||
|
||||
p3d->SetScale(m_Transform.scaling.x(), m_Transform.scaling.y(), m_Transform.scaling.z());
|
||||
p3d->SetUserMatrix(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +199,7 @@ public:
|
||||
}
|
||||
|
||||
if (root) {
|
||||
// Now that we use internal TRS, the prop's total matrix is GetMatrix()
|
||||
m_HighlightActor->SetUserMatrix(root->GetMatrix());
|
||||
}
|
||||
|
||||
@@ -227,6 +224,15 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Puppet::Puppet() : Object(), pd(new PuppetData) {
|
||||
ULIB_ACTIVATE_DISPLAY_PROPERTIES;
|
||||
for (auto* p : this->GetDisplayProperties()) {
|
||||
@@ -278,6 +284,16 @@ void Puppet::RemoveProp(vtkProp *prop)
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Puppet::ApplyAppearance(vtkProp* prop)
|
||||
{
|
||||
pd->ApplyAppearance(prop);
|
||||
}
|
||||
|
||||
void Puppet::ApplyTransform(vtkProp3D* p3d)
|
||||
{
|
||||
pd->ApplyTransform(p3d);
|
||||
}
|
||||
|
||||
|
||||
vtkPropCollection *Puppet::GetParts()
|
||||
{
|
||||
@@ -485,7 +501,7 @@ void Puppet::SetSelected(bool selected)
|
||||
if (!pd->m_Selectable) return;
|
||||
if (pd->m_Selected == selected) return;
|
||||
pd->m_Selected = selected;
|
||||
pd->UpdateHighlight();0
|
||||
pd->UpdateHighlight();
|
||||
}
|
||||
|
||||
bool Puppet::IsSelected() const
|
||||
@@ -497,31 +513,15 @@ void Puppet::Update()
|
||||
{
|
||||
vtkProp* root = this->GetProp();
|
||||
if (root) {
|
||||
pd->ApplyAppearance(root);
|
||||
|
||||
// Handle transformation synchronization from content
|
||||
if (auto* content = dynamic_cast<uLib::AffineTransform*>(GetContent())) {
|
||||
pd->m_Position = content->GetPosition().cast<double>();
|
||||
pd->m_Orientation = content->GetOrientation().cast<double>();
|
||||
pd->m_Scale = content->GetScale().cast<double>();
|
||||
pd->m_Transform = *content; // Uses TRS(const AffineTransform&)
|
||||
}
|
||||
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
const Matrix4f& emat = content->GetMatrix();
|
||||
for(int i=0; i<4; ++i) for(int j=0; j<4; ++j) vmat->SetElement(i, j, emat(i,j));
|
||||
p3d->SetUserMatrix(vmat);
|
||||
|
||||
// Clear base transform to avoid double-application
|
||||
p3d->SetPosition(0,0,0);
|
||||
p3d->SetOrientation(0,0,0);
|
||||
p3d->SetScale(1,1,1);
|
||||
}
|
||||
}
|
||||
else if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||
p3d->SetPosition(pd->m_Position.data());
|
||||
p3d->SetOrientation(pd->m_Orientation.data());
|
||||
p3d->SetScale(pd->m_Scale.data());
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||
pd->ApplyTransform(p3d);
|
||||
}
|
||||
pd->ApplyAppearance(root);
|
||||
}
|
||||
|
||||
vtkProp3DCollection *props = pd->m_Assembly->GetParts();
|
||||
@@ -564,32 +564,29 @@ void Puppet::SyncFromVtk()
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||
// Handle content synchronization if it's an AffineTransform
|
||||
if (auto* content = dynamic_cast<uLib::AffineTransform*>(GetContent())) {
|
||||
vtkMatrix4x4* vmat = p3d->GetUserMatrix();
|
||||
if (vmat) {
|
||||
Matrix4f emat;
|
||||
for (int i=0; i<4; ++i)
|
||||
for (int j=0; j<4; ++j)
|
||||
emat(i, j) = vmat->GetElement(i, j);
|
||||
content->SetMatrix(emat);
|
||||
|
||||
// Re-sync internal puppet properties from the now-updated content
|
||||
pd->m_Position = content->GetPosition().cast<double>();
|
||||
pd->m_Orientation = content->GetOrientation().cast<double>();
|
||||
pd->m_Scale = content->GetScale().cast<double>();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Update internal puppet properties directly from base components
|
||||
// only if no content exists (old behavior)
|
||||
double pos[3], ori[3], scale[3];
|
||||
p3d->GetPosition(pos);
|
||||
p3d->GetOrientation(ori);
|
||||
p3d->GetScale(scale);
|
||||
for (int i=0; i<3; ++i) {
|
||||
pd->m_Position(i) = pos[i];
|
||||
pd->m_Orientation(i) = ori[i];
|
||||
pd->m_Scale(i) = scale[i];
|
||||
}
|
||||
|
||||
// Convert VTK Degrees to Model Radians
|
||||
content->SetPosition(Vector3f(pos[0], pos[1], pos[2]));
|
||||
content->SetOrientation(Vector3f(ori[0], ori[1], ori[2]) * CLHEP::degree);
|
||||
content->SetScale(Vector3f(scale[0], scale[1], scale[2]));
|
||||
|
||||
// Re-sync internal puppet properties from the now-updated content
|
||||
pd->m_Transform = *content;
|
||||
}
|
||||
else {
|
||||
// Update internal puppet TRS directly from VTK components
|
||||
double pos[3], ori[3], scale[3];
|
||||
p3d->GetPosition(pos);
|
||||
p3d->GetOrientation(ori);
|
||||
p3d->GetScale(scale);
|
||||
pd->m_Transform.position = Vector3f(pos[0], pos[1], pos[2]);
|
||||
// Convert VTK Degrees to internal Radians
|
||||
pd->m_Transform.rotation = Vector3f(ori[0], ori[1], ori[2]) * CLHEP::degree;
|
||||
pd->m_Transform.scaling = Vector3f(scale[0], scale[1], scale[2]);
|
||||
}
|
||||
|
||||
// Notify puppet properties updated
|
||||
@@ -609,9 +606,7 @@ struct TransformProxy {
|
||||
PuppetData* pd;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version) {
|
||||
ar & boost::serialization::make_hrp("Position", pd->m_Position, "mm");
|
||||
ar & boost::serialization::make_hrp("Orientation", pd->m_Orientation, "deg");
|
||||
ar & boost::serialization::make_hrp("Scale", pd->m_Scale, "");
|
||||
ar & boost::serialization::make_nvp("Transform", pd->m_Transform);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
// vtk classes forward declaration //
|
||||
class vtkProp;
|
||||
class vtkProp3D;
|
||||
class vtkPolyData;
|
||||
class vtkPropCollection;
|
||||
class vtkRenderer;
|
||||
@@ -121,6 +122,9 @@ protected:
|
||||
|
||||
void RemoveProp(vtkProp *prop);
|
||||
|
||||
void ApplyAppearance(vtkProp* prop);
|
||||
void ApplyTransform(vtkProp3D* p3d);
|
||||
|
||||
std::vector<uLib::PropertyBase*> m_DisplayProperties;
|
||||
mutable uLib::RecursiveMutex m_UpdateMutex;
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
#include <vtkRenderer.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkTransform.h>
|
||||
#include "Math/Transform.h"
|
||||
#include "Vtk/Math/vtkDense.h"
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
@@ -62,20 +64,23 @@ struct HandlerWidgetData {
|
||||
vtkSmartPointer<::vtkActor> m_RotCam; // Camera ring
|
||||
vtkSmartPointer<::vtkActor> m_ScaleX, m_ScaleY, m_ScaleZ; // Cubes
|
||||
|
||||
// cut plane to see only half of rotation handles
|
||||
vtkSmartPointer<::vtkPlane> m_ClipPlane;
|
||||
|
||||
// picker to select the gizmo
|
||||
vtkSmartPointer<::vtkCellPicker> m_Picker;
|
||||
|
||||
// initial transform of the object
|
||||
vtkSmartPointer<::vtkTransform> m_InitialTransform;
|
||||
|
||||
std::vector<vtkSmartPointer<::vtkTransform>> m_TransformChain;
|
||||
vtkSmartPointer<::vtkMatrix4x4> m_BaseMatrix;
|
||||
// undo stack
|
||||
std::vector<uLib::TRS> m_UndoStack;
|
||||
|
||||
HandlerWidgetData() {
|
||||
m_Picker = vtkSmartPointer<::vtkCellPicker>::New();
|
||||
m_InitialTransform = vtkSmartPointer<::vtkTransform>::New();
|
||||
m_ClipPlane = vtkSmartPointer<::vtkPlane>::New();
|
||||
m_OverlayRenderer = vtkSmartPointer<::vtkRenderer>::New();
|
||||
m_BaseMatrix = vtkSmartPointer<::vtkMatrix4x4>::New();
|
||||
m_HighlightedProp = nullptr;
|
||||
}
|
||||
};
|
||||
@@ -95,7 +100,6 @@ vtkHandlerWidget::vtkHandlerWidget() : d(new HandlerWidgetData()) {
|
||||
this->m_TranslationEnabled = true;
|
||||
this->m_RotationEnabled = true;
|
||||
this->m_ScalingEnabled = true;
|
||||
d->m_BaseMatrix->Identity();
|
||||
this->CreateGizmos();
|
||||
}
|
||||
|
||||
@@ -108,19 +112,14 @@ vtkHandlerWidget::~vtkHandlerWidget() {
|
||||
return d->m_OverlayRenderer;
|
||||
}
|
||||
|
||||
|
||||
void vtkHandlerWidget::SetProp3D(::vtkProp3D *prop) {
|
||||
if (this->Prop3D == prop) {
|
||||
return;
|
||||
}
|
||||
this->Prop3D = prop;
|
||||
if (this->Prop3D) {
|
||||
// Initialize d->m_BaseMatrix from the object's current matrix
|
||||
if (this->Prop3D->GetUserMatrix()) {
|
||||
this->d->m_BaseMatrix->DeepCopy(this->Prop3D->GetUserMatrix());
|
||||
} else {
|
||||
this->d->m_BaseMatrix->Identity();
|
||||
}
|
||||
this->d->m_TransformChain.clear(); // Clear any previous transform chain
|
||||
this->d->m_UndoStack.clear(); // Clear history when selecting new object
|
||||
this->UpdateGizmoPosition();
|
||||
}
|
||||
this->Modified();
|
||||
@@ -247,20 +246,19 @@ void vtkHandlerWidget::OnKeyPress() {
|
||||
bool ctrl = (this->Interactor->GetControlKey() != 0);
|
||||
|
||||
if (ctrl && key == "z") {
|
||||
if (!this->d->m_TransformChain.empty()) {
|
||||
if (!this->d->m_UndoStack.empty()) {
|
||||
std::cout << "Undoing last transform action..." << std::endl;
|
||||
this->d->m_TransformChain.pop_back();
|
||||
uLib::TRS target = this->d->m_UndoStack.back();
|
||||
this->d->m_UndoStack.pop_back();
|
||||
|
||||
// Update object from chain
|
||||
vtkNew<vtkTransform> total;
|
||||
total->PostMultiply();
|
||||
total->SetMatrix(this->d->m_BaseMatrix.GetPointer());
|
||||
for (auto& t : d->m_TransformChain) {
|
||||
total->Concatenate(t);
|
||||
}
|
||||
|
||||
if (this->Prop3D && this->Prop3D->GetUserMatrix()) {
|
||||
this->Prop3D->GetUserMatrix()->DeepCopy(total->GetMatrix());
|
||||
if (this->Prop3D) {
|
||||
this->Prop3D->SetPosition(target.position.x(), target.position.y(), target.position.z());
|
||||
// Convert Model Radians to VTK Degrees
|
||||
this->Prop3D->SetOrientation(target.rotation.x() / CLHEP::degree,
|
||||
target.rotation.y() / CLHEP::degree,
|
||||
target.rotation.z() / CLHEP::degree);
|
||||
this->Prop3D->SetScale(target.scaling.x(), target.scaling.y(), target.scaling.z());
|
||||
this->Prop3D->SetUserMatrix(nullptr);
|
||||
this->Prop3D->Modified();
|
||||
this->UpdateGizmoPosition();
|
||||
this->InvokeEvent(::vtkCommand::InteractionEvent, nullptr);
|
||||
@@ -311,21 +309,12 @@ void vtkHandlerWidget::OnLeftButtonDown() {
|
||||
this->StartEventPosition[0] = X;
|
||||
this->StartEventPosition[1] = Y;
|
||||
if (this->Prop3D) {
|
||||
if (!this->Prop3D->GetUserMatrix()) {
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
this->Prop3D->SetUserMatrix(vmat);
|
||||
}
|
||||
|
||||
// If the chain is empty, initialize base from current state?
|
||||
// Actually, if we just started selecting this object, we should have initialized BaseMatrix.
|
||||
// For now, let's keep d->m_InitialTransform as the state BEFORE this drag
|
||||
vtkNew<vtkTransform> current;
|
||||
current->PostMultiply();
|
||||
current->SetMatrix(this->d->m_BaseMatrix.GetPointer());
|
||||
for (auto& t : d->m_TransformChain) {
|
||||
current->Concatenate(t);
|
||||
}
|
||||
this->d->m_InitialTransform->SetMatrix(current->GetMatrix());
|
||||
// Capture current state for Undo
|
||||
this->d->m_UndoStack.push_back(uLib::TRS(uLib::Vtk::VtkToMatrix4f(this->Prop3D->GetMatrix())));
|
||||
if (this->d->m_UndoStack.size() > 50) this->d->m_UndoStack.erase(this->d->m_UndoStack.begin());
|
||||
|
||||
// Use the prop's total matrix for calculation baseline
|
||||
this->d->m_InitialTransform->SetMatrix(this->Prop3D->GetMatrix());
|
||||
}
|
||||
this->EventCallbackCommand->SetAbortFlag(1);
|
||||
this->InvokeEvent(::vtkCommand::StartInteractionEvent, nullptr);
|
||||
@@ -337,27 +326,6 @@ void vtkHandlerWidget::OnLeftButtonUp() {
|
||||
if (this->Interaction == IDLE)
|
||||
return;
|
||||
|
||||
// Finalize the current interaction into the chain
|
||||
int X = this->Interactor->GetEventPosition()[0];
|
||||
int Y = this->Interactor->GetEventPosition()[1];
|
||||
|
||||
// We need to re-calculate the final 'op' to store it
|
||||
// Actually, we could have stored it in OnMouseMove, but let's re-calculate or
|
||||
// just capture the delta between d->m_InitialTransform and current UserMatrix.
|
||||
if (this->Prop3D && this->Prop3D->GetUserMatrix()) {
|
||||
vtkNew<vtkMatrix4x4> inv;
|
||||
vtkMatrix4x4::Invert(this->d->m_InitialTransform->GetMatrix(), inv);
|
||||
|
||||
vtkNew<vtkMatrix4x4> final_op_mat;
|
||||
vtkMatrix4x4::Multiply4x4(this->Prop3D->GetUserMatrix(), inv, final_op_mat);
|
||||
|
||||
vtkNew<vtkTransform> final_op;
|
||||
final_op->SetMatrix(final_op_mat);
|
||||
|
||||
this->d->m_TransformChain.push_back(final_op);
|
||||
std::cout << "Action finalized. Chain size: " << this->d->m_TransformChain.size() << std::endl;
|
||||
}
|
||||
|
||||
this->Interaction = IDLE;
|
||||
this->EventCallbackCommand->SetAbortFlag(1);
|
||||
this->InvokeEvent(::vtkCommand::EndInteractionEvent, nullptr);
|
||||
@@ -578,9 +546,17 @@ void vtkHandlerWidget::OnMouseMove() {
|
||||
total->SetMatrix(this->d->m_InitialTransform->GetMatrix()); // d->m_InitialTransform is already Base*Chain
|
||||
total->Concatenate(op);
|
||||
|
||||
vtkMatrix4x4* targetMat = this->Prop3D->GetUserMatrix();
|
||||
if (targetMat) {
|
||||
targetMat->DeepCopy(total->GetMatrix());
|
||||
if (this->Prop3D) {
|
||||
double p[3], r[3], s[3];
|
||||
total->GetPosition(p);
|
||||
total->GetOrientation(r);
|
||||
total->GetScale(s);
|
||||
this->Prop3D->SetPosition(p);
|
||||
// VTK GetOrientation already returned degrees, so r is in degrees.
|
||||
// We apply it directly back to VTK.
|
||||
this->Prop3D->SetOrientation(r);
|
||||
this->Prop3D->SetScale(s);
|
||||
this->Prop3D->SetUserMatrix(nullptr);
|
||||
}
|
||||
|
||||
this->Prop3D->Modified();
|
||||
@@ -671,7 +647,7 @@ void vtkHandlerWidget::SetTransform(::vtkTransform *t) {
|
||||
void vtkHandlerWidget::GetTransform(::vtkTransform *t) {
|
||||
if (!t || !this->Prop3D)
|
||||
return;
|
||||
t->SetMatrix(this->Prop3D->GetUserMatrix());
|
||||
t->SetMatrix(this->Prop3D->GetMatrix());
|
||||
}
|
||||
|
||||
void vtkHandlerWidget::CreateGizmos() {
|
||||
|
||||
@@ -209,7 +209,6 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren)
|
||||
for (auto* p : self->m_Puppets) {
|
||||
if (p->IsSelected()) {
|
||||
p->SyncFromVtk();
|
||||
p->Update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user