/*////////////////////////////////////////////////////////////////////////////// // 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), m_BlockUpdate(false) { this->InstallPipe(); if (m_Content) { Object::connect(m_Content, &uLib::Assembly::Updated, this, &Assembly::contentUpdate); } } 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(); 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->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); // The vtkObjectsContext's own prop is already a ::vtkAssembly; // nest it inside ours so everything moves together. if (auto *childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) m_VtkAsm->AddPart(childProp); } // 4. Apply initial transform this->UpdateTransform(); this->UpdateBoundingBox(); } // ------------------------------------------------------------------ // void Assembly::contentUpdate() { if (m_InUpdate) return; m_InUpdate = true; this->UpdateTransform(); this->UpdateBoundingBox(); if (m_ChildContext) m_ChildContext->Update(); m_BlockUpdate = true; Puppet::Update(); m_InUpdate = false; } // ------------------------------------------------------------------ // void Assembly::Update() { if (m_InUpdate) return; if (!m_Content || !m_VtkAsm) return; if (m_BlockUpdate) { m_BlockUpdate = false; 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); } this->UpdateBoundingBox(); if (m_ChildContext) m_ChildContext->Update(); m_Content->Updated(); // Notify change in model m_InUpdate = false; } // ------------------------------------------------------------------ // void Assembly::UpdateTransform() { if (!m_Content || !m_VtkAsm) return; Matrix4f mat = m_Content->GetMatrix(); vtkNew vmat; Matrix4fToVtk(mat, vmat); m_VtkAsm->SetUserMatrix(vmat); m_VtkAsm->Modified(); } // ------------------------------------------------------------------ // 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