refactor: update Puppet transform logic to support AffineTransform world matrices and improve selection highlighting

This commit is contained in:
AndreaRigoni
2026-03-30 15:24:37 +00:00
parent 46c39bc26e
commit 22d0041942
24 changed files with 469 additions and 331 deletions

View File

@@ -80,7 +80,8 @@ namespace Vtk {
class PuppetData {
public:
PuppetData() :
PuppetData(Puppet* owner) :
m_Puppet(owner),
m_Renderers(vtkSmartPointer<vtkRendererCollection>::New()),
m_Assembly(vtkSmartPointer<vtkAssembly>::New()),
m_ShowBoundingBox(false),
@@ -99,9 +100,10 @@ public:
// No manual Delete needed for smart pointers
}
Puppet *m_Puppet;
// members //
vtkSmartPointer<vtkRendererCollection> m_Renderers;
vtkSmartPointer<vtkAssembly> m_Assembly;
vtkSmartPointer<vtkAssembly> m_Assembly;
vtkSmartPointer<vtkOutlineSource> m_OutlineSource;
vtkSmartPointer<vtkActor> m_OutlineActor;
@@ -118,6 +120,8 @@ public:
bool m_Selected;
bool m_Visibility;
bool m_Dragable;
//
TRS m_Transform;
void ApplyAppearance(vtkProp *p) {
@@ -157,20 +161,49 @@ public:
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);
if (auto* content = dynamic_cast<uLib::AffineTransform*>(m_Puppet->GetContent())) {
vtkNew<vtkMatrix4x4> m;
Matrix4fToVtk(content->GetWorldMatrix(), m);
p3d->SetUserMatrix(m);
} else {
p3d->SetUserMatrix(nullptr);
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());
}
}
}
void UpdateHighlight() {
if (m_Selected) {
// Find first polydata in assembly to highlight
vtkPolyData* polydata = nullptr;
vtkPropCollection *parts = m_Assembly->GetParts();
parts->InitTraversal();
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
vtkActor *actor = vtkActor::SafeDownCast(parts->GetNextProp());
if (actor && actor->GetMapper()) {
polydata = vtkPolyData::SafeDownCast(actor->GetMapper()->GetDataSetInput());
if (polydata) break;
}
}
if (!polydata) {
if (m_HighlightActor) {
m_Renderers->InitTraversal();
for (int i = 0; i < m_Renderers->GetNumberOfItems(); ++i) {
m_Renderers->GetNextItem()->RemoveActor(m_HighlightActor);
}
m_HighlightActor = nullptr;
}
return;
}
if (!m_HighlightActor) {
vtkSmartPointer<vtkFeatureEdges> edges = vtkSmartPointer<vtkFeatureEdges>::New();
edges->BoundaryEdgesOn();
@@ -178,17 +211,7 @@ public:
edges->SetFeatureAngle(30);
edges->NonManifoldEdgesOn();
edges->ManifoldEdgesOff();
// Find first polydata in assembly to highlight
vtkPropCollection *parts = m_Assembly->GetParts();
parts->InitTraversal();
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
vtkActor *actor = vtkActor::SafeDownCast(parts->GetNextProp());
if (actor && actor->GetMapper() && actor->GetMapper()->GetDataSetInput()) {
edges->SetInputData(vtkPolyData::SafeDownCast(actor->GetMapper()->GetDataSetInput()));
break;
}
}
edges->SetInputData(polydata);
m_HighlightActor = vtkSmartPointer<vtkActor>::New();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
@@ -197,6 +220,13 @@ public:
m_HighlightActor->GetProperty()->SetColor(1.0, 0.5, 0.0); // Orange
m_HighlightActor->GetProperty()->SetLineWidth(2.0);
m_HighlightActor->GetProperty()->SetLighting(0);
} else {
// Update input data (safe even if same)
if (auto* mapper = vtkPolyDataMapper::SafeDownCast(m_HighlightActor->GetMapper())) {
if (auto* edges = vtkFeatureEdges::SafeDownCast(mapper->GetInputAlgorithm())) {
edges->SetInputData(polydata);
}
}
}
// Update highlight matrix from the root prop
@@ -208,7 +238,6 @@ public:
}
if (root) {
// Now that we use internal TRS, the prop's total matrix is GetMatrix()
m_HighlightActor->SetUserMatrix(root->GetMatrix());
}
@@ -242,7 +271,7 @@ public:
Puppet::Puppet() : Object(), pd(new PuppetData) {
Puppet::Puppet() : Object(), pd(new PuppetData(this)) {
ULIB_ACTIVATE_DISPLAY_PROPERTIES;
for (auto* p : this->GetDisplayProperties()) {
uLib::Object::connect(p, &uLib::PropertyBase::Updated, this, &Puppet::Update);
@@ -576,36 +605,27 @@ 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())) {
double pos[3], ori[3], scale[3];
p3d->GetPosition(pos);
p3d->GetOrientation(ori);
p3d->GetScale(scale);
// Apply current VTK world transform to model.
// When 'sinking the chain', p3d's matrix represents the world matrix
// because it has no parent in VTK (nesting was removed).
vtkNew<vtkMatrix4x4> m;
p3d->GetMatrix(m);
content->SetWorldMatrix(VtkToMatrix4f(m));
// 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
// Sync local TRS from the newly updated model
pd->m_Transform = *content;
}
else {
// Update internal puppet TRS directly from VTK components
// Fallback for simple props
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]);
pd->m_Transform.scaling = Vector3f(scale[0], scale[1], scale[2]);
}
// Notify puppet properties updated
if (auto* propPos = this->GetProperty("Position")) propPos->Updated();
if (auto* propOri = this->GetProperty("Orientation")) propOri->Updated();
if (auto* propScale = this->GetProperty("Scale")) propScale->Updated();
this->Object::Updated();
}
}
@@ -614,6 +634,11 @@ void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor)
{
}
// ------------------------------------------------------ //
// SERIALIZE DISPLAY PROPERTIES
struct TransformProxy {
PuppetData* pd;
template<class Archive>
@@ -643,13 +668,6 @@ void Puppet::serialize_display(Archive::display_properties_archive & ar, const u
ar & boost::serialization::make_nvp("Transform", transform);
}
void Puppet::serialize(Archive::xml_oarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::xml_iarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::text_oarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::text_iarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::hrt_oarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::hrt_iarchive & ar, const unsigned int v) { }
void Puppet::serialize(Archive::log_archive & ar, const unsigned int v) { }
} // namespace Vtk
} // namespace uLib