Files
uLib/src/Vtk/Math/vtkAssembly.cpp

198 lines
5.8 KiB
C++

/*//////////////////////////////////////////////////////////////////////////////
// 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 >
//////////////////////////////////////////////////////////////////////////////*/
#include "vtkAssembly.h" // uLib::Vtk::Assembly
#include "Vtk/vtkObjectsContext.h"
#include "Math/vtkDense.h"
#include <vtkAssembly.h> // VTK library ::vtkAssembly
#include <vtkActor.h>
#include <vtkCubeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkMatrix4x4.h>
#include <vtkPropCollection.h>
#include <vtkNew.h>
#include <vtkProp3D.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyData.h>
namespace uLib {
namespace Vtk {
// ------------------------------------------------------------------ //
Assembly::Assembly(uLib::Assembly *content)
: m_Content(content),
m_ChildContext(nullptr),
m_BBoxActor(nullptr),
m_VtkAsm(nullptr),
m_InUpdate(false) {
this->InstallPipe();
if (m_Content) {
Object::connect(m_Content, &uLib::Assembly::Updated,
this, &Assembly::Update);
}
}
Assembly::~Assembly() {
delete m_ChildContext;
if (m_BBoxActor) m_BBoxActor->Delete();
if (m_VtkAsm) m_VtkAsm->Delete();
}
// ------------------------------------------------------------------ //
void Assembly::InstallPipe() {
// 1. Create the VTK library assembly that groups everything
m_VtkAsm = ::vtkAssembly::New();
m_VtkAsm->PickableOff();
this->SetProp(m_VtkAsm);
// 2. Create the bounding-box wireframe actor
vtkNew<vtkCubeSource> cube;
cube->SetBounds(0, 1, 0, 1, 0, 1);
cube->Update();
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(cube->GetOutputPort());
m_BBoxActor = vtkActor::New();
m_BBoxActor->SetMapper(mapper);
m_BBoxActor->GetProperty()->SetRepresentationToWireframe();
m_BBoxActor->GetProperty()->SetColor(1.0, 0.85, 0.0); // gold wireframe
m_BBoxActor->GetProperty()->SetLineWidth(1.5);
m_BBoxActor->GetProperty()->SetOpacity(0.6);
m_BBoxActor->PickableOff();
m_BBoxActor->SetVisibility(m_Content ? m_Content->GetShowBoundingBox() : false);
m_VtkAsm->AddPart(m_BBoxActor);
// 3. Build a child-objects context (auto-creates puppets for each child)
if (m_Content) {
m_ChildContext = new vtkObjectsContext(m_Content);
// Link the children context's assembly into our group assembly
if (auto* childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) {
m_VtkAsm->AddPart(childProp);
}
}
// 4. Force initial visual sync
this->Update();
}
// ------------------------------------------------------------------ //
void Assembly::Update() {
if (m_InUpdate) return;
m_InUpdate = true;
if (m_Content && m_VtkAsm) {
// Apply world matrix from the assembly content
vtkNew<vtkMatrix4x4> m;
Matrix4fToVtk(m_Content->GetMatrix(), m);
m_VtkAsm->SetUserMatrix(m);
m_VtkAsm->Modified();
}
this->Puppet::Update();
this->UpdateBoundingBox();
if (m_ChildContext)
m_ChildContext->Update();
m_InUpdate = false;
}
void Assembly::SyncFromVtk() {
if (m_InUpdate) return;
if (!m_Content || !m_VtkAsm) return;
m_InUpdate = true;
// VTK -> Model: Update world matrix (accounting for model parents)
if (vtkProp3D* proxy = this->GetProxyProp()) {
m_Content->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix()));
m_Content->FromMatrix(m_Content->GetMatrix());
}
this->UpdateBoundingBox();
if (m_ChildContext)
m_ChildContext->SyncFromVtk();
m_Content->Updated(); // Notify change in model
m_InUpdate = false;
}
// ------------------------------------------------------------------ //
void Assembly::UpdateBoundingBox() {
if (!m_Content || !m_BBoxActor) return;
m_BBoxActor->SetVisibility(m_Content->GetShowBoundingBox());
Vector3f bbMin, bbMax;
m_Content->GetBoundingBox(bbMin, bbMax);
// Avoid degenerate boxes
Vector3f size = bbMax - bbMin;
if (size.norm() < 1e-6f) return;
// Rebuild the corner segments to match the AABB
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> lines;
float bounds[2][3] = {
{bbMin(0), bbMin(1), bbMin(2)},
{bbMax(0), bbMax(1), bbMax(2)}
};
// Corner segment length: 10% of dimension
float len[3] = {
(bbMax(0) - bbMin(0)) * 0.1f,
(bbMax(1) - bbMin(1)) * 0.1f,
(bbMax(2) - bbMin(2)) * 0.1f
};
for (int i = 0; i < 8; ++i) {
float p[3];
p[0] = bounds[(i & 1) ? 1 : 0][0];
p[1] = bounds[(i & 2) ? 1 : 0][1];
p[2] = bounds[(i & 4) ? 1 : 0][2];
for (int axis = 0; axis < 3; ++axis) {
float p2[3] = {p[0], p[1], p[2]};
float delta = (i & (1 << axis)) ? -len[axis] : len[axis];
p2[axis] += delta;
vtkIdType id1 = points->InsertNextPoint(p);
vtkIdType id2 = points->InsertNextPoint(p2);
lines->InsertNextCell(2);
lines->InsertCellPoint(id1);
lines->InsertCellPoint(id2);
}
}
vtkNew<vtkPolyData> poly;
poly->SetPoints(points);
poly->SetLines(lines);
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(poly);
m_BBoxActor->SetMapper(mapper);
m_BBoxActor->Modified();
}
// ------------------------------------------------------------------ //
vtkObjectsContext *Assembly::GetChildrenContext() const {
return m_ChildContext;
}
} // namespace Vtk
} // namespace uLib