/*////////////////////////////////////////////////////////////////////////////// // 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 // VTK library ::vtkAssembly #include #include #include #include #include #include #include #include #include #include #include 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 cube; cube->SetBounds(0, 1, 0, 1, 0, 1); cube->Update(); vtkNew 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 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 points; vtkNew 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 poly; poly->SetPoints(points); poly->SetLines(lines); vtkNew mapper; mapper->SetInputData(poly); m_BBoxActor->SetMapper(mapper); m_BBoxActor->Modified(); } // ------------------------------------------------------------------ // vtkObjectsContext *Assembly::GetChildrenContext() const { return m_ChildContext; } } // namespace Vtk } // namespace uLib