/*////////////////////////////////////////////////////////////////////////////// // 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. //////////////////////////////////////////////////////////////////////////////*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uLibVtkViewer.h" // Custom interactor style: disables spin/inertia so the scene only // rotates while the mouse is actively being moved with the button held. class vtkInteractorStyleNoSpin : public vtkInteractorStyleTrackballCamera { public: static vtkInteractorStyleNoSpin *New(); vtkTypeMacro(vtkInteractorStyleNoSpin, vtkInteractorStyleTrackballCamera); // Override: when the left button is released, immediately stop any // ongoing motion (rotation/spin) so no momentum is carried over. void OnLeftButtonUp() override { this->StopState(); vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); } }; vtkStandardNewMacro(vtkInteractorStyleNoSpin); namespace uLib { namespace Vtk { struct ViewerData { vtkRenderWindow *m_RenderWindow; vtkSmartPointer m_GridButton; ViewerData() : m_RenderWindow(vtkRenderWindow::New()) {} ~ViewerData() { m_RenderWindow->Delete(); } }; //////////////////////////////////////////////////////////////////////////////// ///// VTK VIEWER ////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// Viewer::Viewer() : Viewport(), d(new ViewerData()) { InstallPipe(); } Viewer::~Viewer() { UninstallPipe(); delete d; } void Viewer::InstallPipe() { d->m_RenderWindow->AddRenderer(this->GetRenderer()); d->m_RenderWindow->SetSize(600,600); vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); renderWindowInteractor->SetRenderWindow(d->m_RenderWindow); // Common setup Viewport::SetupPipeline(renderWindowInteractor); // Setup native grid button SetupGridButton(); // BUT we want to override the style with our custom NoSpin version vtkSmartPointer style = vtkSmartPointer::New(); renderWindowInteractor->SetInteractorStyle(style); // Must be rendered here in Vtk-6.0 or seg-fault // d->m_RenderWindow->Render(); } void Viewer::UninstallPipe() { if (GetRenderer()) { GetRenderer()->RemoveAllViewProps(); } } void Viewer::Render() { if (d->m_RenderWindow) d->m_RenderWindow->Render(); } vtkCameraOrientationWidget * Viewer::MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor, vtkRenderer *renderer) { vtkSmartPointer widget = vtkSmartPointer::New(); widget->SetParentRenderer(renderer); widget->SetInteractor(interactor); widget->On(); return widget; } void Viewer::SetupGridButton() { if (!d->m_RenderWindow || !d->m_RenderWindow->GetInteractor()) return; // Create procedural textures for the button using canvas vtkNew canvas; canvas->SetScalarTypeToUnsignedChar(); canvas->SetNumberOfScalarComponents(4); canvas->SetExtent(0, 63, 0, 63, 0, 0); // State 0: OFF (Gray circle, transparent background) canvas->SetDrawColor(0, 0, 0, 0); canvas->FillBox(0, 63, 0, 63); canvas->SetDrawColor(120, 120, 120, 255); canvas->DrawCircle(32, 32, 25); canvas->Update(); vtkNew imgOff; imgOff->DeepCopy(canvas->GetOutput()); // State 1: ON (White circle, transparent background) canvas->SetDrawColor(0, 0, 0, 0); canvas->FillBox(0, 63, 0, 63); canvas->SetDrawColor(255, 255, 255, 255); canvas->DrawCircle(32, 32, 25); canvas->Update(); vtkNew imgOn; imgOn->DeepCopy(canvas->GetOutput()); vtkNew rep; rep->SetNumberOfStates(2); rep->SetButtonTexture(0, imgOff); rep->SetButtonTexture(1, imgOn); d->m_GridButton = vtkSmartPointer::New(); d->m_GridButton->SetInteractor(d->m_RenderWindow->GetInteractor()); d->m_GridButton->SetRepresentation(rep); // Position it initially UpdateGridButtonPosition(); // Callback for resize (ModifiedEvent on RenderWindow) vtkNew resizeCallback; resizeCallback->SetClientData(this); resizeCallback->SetCallback([](vtkObject*, unsigned long, void* clientdata, void*){ auto* v = static_cast(clientdata); v->UpdateGridButtonPosition(); }); d->m_RenderWindow->AddObserver(vtkCommand::ModifiedEvent, resizeCallback); // Callback for state change vtkNew stateCallback; stateCallback->SetClientData(this); stateCallback->SetCallback([](vtkObject* caller, unsigned long, void* clientdata, void*){ auto* btn = vtkButtonWidget::SafeDownCast(caller); auto* v = static_cast(clientdata); auto* r = vtkTexturedButtonRepresentation2D::SafeDownCast(btn->GetRepresentation()); v->SetGridVisible(r->GetState() == 1); }); d->m_GridButton->AddObserver(vtkCommand::StateChangedEvent, stateCallback); d->m_GridButton->On(); // Set initial state rep->SetState(GetGridVisible() ? 1 : 0); } void Viewer::UpdateGridButtonPosition() { if (!d->m_GridButton || !d->m_RenderWindow) return; auto* rep = vtkTexturedButtonRepresentation2D::SafeDownCast(d->m_GridButton->GetRepresentation()); if (!rep) return; int *sz = d->m_RenderWindow->GetSize(); if (sz[0] == 0 || sz[1] == 0) return; // Window not yet sized or hidden int margin_rigth = 23; int margin_top = 170; int btnSz = 100; // Button size in display coordinates double bds[6] = { (double)sz[0] - btnSz - margin_rigth, (double)sz[0] - margin_rigth, (double)sz[1] - margin_top - btnSz/2.0, (double)sz[1] - margin_top + btnSz/2.0, 0, 0 }; rep->PlaceWidget(bds); } void Viewer::Start() { d->m_RenderWindow->GetInteractor()->Start(); } vtkRenderWindow *Viewer::GetRenderWindow() { return d->m_RenderWindow; } vtkRenderWindowInteractor *Viewer::GetInteractor() { return d->m_RenderWindow->GetInteractor(); } } // namespace Vtk } // namespace uLib