From 1374821344ad238a7643dab26dc9224767f0b6f2 Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Sun, 8 Mar 2026 10:21:38 +0000 Subject: [PATCH] added gizmo but not yet working --- src/Vtk/CMakeLists.txt | 8 +- src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx | 11 +- src/Vtk/HEP/Detectors/vtkDetectorChamber.h | 6 +- src/Vtk/vtkHandlerWidget.cpp | 366 +++++++++++++++++++ src/Vtk/vtkHandlerWidget.h | 111 ++++++ 5 files changed, 491 insertions(+), 11 deletions(-) create mode 100644 src/Vtk/vtkHandlerWidget.cpp create mode 100644 src/Vtk/vtkHandlerWidget.h diff --git a/src/Vtk/CMakeLists.txt b/src/Vtk/CMakeLists.txt index 4ba3acd..b8bce7c 100644 --- a/src/Vtk/CMakeLists.txt +++ b/src/Vtk/CMakeLists.txt @@ -1,10 +1,14 @@ set(HEADERS uLibVtkInterface.h uLibVtkViewer.h - vtkContainerBox.h) + vtkContainerBox.h + vtkHandlerWidget.h + ) set(SOURCES uLibVtkInterface.cxx uLibVtkViewer.cpp - vtkContainerBox.cpp) + vtkContainerBox.cpp + vtkHandlerWidget.cpp + ) ## Pull in Math VTK wrappers (sets MATH_SOURCES / MATH_HEADERS) add_subdirectory(Math) diff --git a/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx b/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx index 7a4c700..a75d09c 100644 --- a/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx +++ b/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx @@ -24,7 +24,6 @@ //////////////////////////////////////////////////////////////////////////////*/ #include -#include #include #include #include @@ -39,22 +38,20 @@ #include #include "Vtk/HEP/Detectors/vtkDetectorChamber.h" +#include "Vtk/vtkHandlerWidget.h" namespace uLib { namespace Vtk { vtkDetectorChamber::vtkDetectorChamber(DetectorChamber *content) : vtkContainerBox(content) { - m_Widget = vtkBoxWidget::New(); + m_Widget = vtkHandlerWidget::New(); m_Callback = vtkWidgetCallback::New(); m_PickerCallback = vtkSelectionCallback::New(); m_Callback->SetChamber(this); m_PickerCallback->SetChamber(this); m_Widget->AddObserver(vtkCommand::InteractionEvent, m_Callback); - m_Widget->SetRotationEnabled(1); - m_Widget->SetTranslationEnabled(1); - m_Widget->SetScalingEnabled(0); } vtkDetectorChamber::~vtkDetectorChamber() { @@ -139,7 +136,7 @@ void vtkDetectorChamber::InstallPipe() { void vtkDetectorChamber::vtkWidgetCallback::Execute(vtkObject *caller, unsigned long, void *) { - vtkBoxWidget *widget = reinterpret_cast(caller); + vtkHandlerWidget *widget = reinterpret_cast(caller); vtkSmartPointer t = vtkSmartPointer::New(); widget->GetTransform(t); @@ -185,6 +182,8 @@ void vtkDetectorChamber::vtkSelectionCallback::Execute(vtkObject *caller, vtkSmartPointer t = vtkSmartPointer::New(); t->SetMatrix(vmat); + chamber->m_Widget->SetCurrentRenderer( + interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()); chamber->m_Widget->SetTransform(t); chamber->m_Widget->PlaceWidget(); chamber->m_Widget->On(); diff --git a/src/Vtk/HEP/Detectors/vtkDetectorChamber.h b/src/Vtk/HEP/Detectors/vtkDetectorChamber.h index 157759a..6446d9f 100644 --- a/src/Vtk/HEP/Detectors/vtkDetectorChamber.h +++ b/src/Vtk/HEP/Detectors/vtkDetectorChamber.h @@ -36,11 +36,11 @@ #include "Vtk/uLibVtkInterface.h" #include "Vtk/vtkContainerBox.h" -class vtkBoxWidget; - namespace uLib { namespace Vtk { +class vtkHandlerWidget; + class vtkDetectorChamber : public vtkContainerBox { typedef DetectorChamber Content; @@ -80,7 +80,7 @@ private: uLib::Vtk::vtkDetectorChamber *chamber; }; - vtkBoxWidget *m_Widget; + vtkHandlerWidget *m_Widget; vtkWidgetCallback *m_Callback; vtkSelectionCallback *m_PickerCallback; }; diff --git a/src/Vtk/vtkHandlerWidget.cpp b/src/Vtk/vtkHandlerWidget.cpp new file mode 100644 index 0000000..41e3475 --- /dev/null +++ b/src/Vtk/vtkHandlerWidget.cpp @@ -0,0 +1,366 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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. + +//////////////////////////////////////////////////////////////////////////////*/ + +#include "vtkHandlerWidget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uLib { +namespace Vtk { + +vtkStandardNewMacro(vtkHandlerWidget); + +vtkHandlerWidget::vtkHandlerWidget() { + this->Interaction = IDLE; + this->m_Picker = vtkSmartPointer<::vtkPropPicker>::New(); + this->m_InitialTransform = vtkSmartPointer<::vtkTransform>::New(); + this->EventCallbackCommand->SetCallback(vtkHandlerWidget::ProcessEvents); + this->EventCallbackCommand->SetClientData(this); + this->CreateGizmos(); +} + +vtkHandlerWidget::~vtkHandlerWidget() {} + +void vtkHandlerWidget::SetEnabled(int enabling) { + if (enabling) { + if (this->Enabled) + return; + if (!this->Interactor) { + vtkErrorMacro( + << "The interactor must be set prior to enabling the widget"); + return; + } + + if (!this->CurrentRenderer) { + this->CurrentRenderer = this->Interactor->FindPokedRenderer( + this->Interactor->GetLastEventPosition()[0], + this->Interactor->GetLastEventPosition()[1]); + } + + if (!this->CurrentRenderer) { + return; + } + + this->Enabled = 1; + + // Add observers + ::vtkRenderWindowInteractor *i = this->Interactor; + i->AddObserver(::vtkCommand::LeftButtonPressEvent, + this->EventCallbackCommand, this->Priority); + i->AddObserver(::vtkCommand::LeftButtonReleaseEvent, + this->EventCallbackCommand, this->Priority); + i->AddObserver(::vtkCommand::MouseMoveEvent, this->EventCallbackCommand, + this->Priority); + + this->UpdateGizmoPosition(); + this->CurrentRenderer->AddActor(m_AxesX); + this->CurrentRenderer->AddActor(m_AxesY); + this->CurrentRenderer->AddActor(m_AxesZ); + this->CurrentRenderer->AddActor(m_RotX); + this->CurrentRenderer->AddActor(m_RotY); + this->CurrentRenderer->AddActor(m_RotZ); + this->CurrentRenderer->AddActor(m_ScaleX); + this->CurrentRenderer->AddActor(m_ScaleY); + this->CurrentRenderer->AddActor(m_ScaleZ); + + this->InvokeEvent(::vtkCommand::EnableEvent, nullptr); + } else { + if (!this->Enabled) + return; + + this->Enabled = 0; + this->Interactor->RemoveObserver(this->EventCallbackCommand); + if (this->CurrentRenderer) { + this->CurrentRenderer->RemoveActor(m_AxesX); + this->CurrentRenderer->RemoveActor(m_AxesY); + this->CurrentRenderer->RemoveActor(m_AxesZ); + this->CurrentRenderer->RemoveActor(m_RotX); + this->CurrentRenderer->RemoveActor(m_RotY); + this->CurrentRenderer->RemoveActor(m_RotZ); + this->CurrentRenderer->RemoveActor(m_ScaleX); + this->CurrentRenderer->RemoveActor(m_ScaleY); + this->CurrentRenderer->RemoveActor(m_ScaleZ); + } + this->InvokeEvent(::vtkCommand::DisableEvent, nullptr); + } + + if (this->Interactor) { + this->Interactor->Render(); + } +} + +void vtkHandlerWidget::ProcessEvents(::vtkObject *caller, unsigned long event, + void *clientdata, void *calldata) { + (void)caller; + (void)calldata; + vtkHandlerWidget *self = reinterpret_cast(clientdata); + switch (event) { + case ::vtkCommand::LeftButtonPressEvent: + self->OnLeftButtonDown(); + break; + case ::vtkCommand::LeftButtonReleaseEvent: + self->OnLeftButtonUp(); + break; + case ::vtkCommand::MouseMoveEvent: + self->OnMouseMove(); + break; + } +} + +void vtkHandlerWidget::OnLeftButtonDown() { + int X = this->Interactor->GetEventPosition()[0]; + int Y = this->Interactor->GetEventPosition()[1]; + + if (!this->CurrentRenderer) { + this->CurrentRenderer = this->Interactor->FindPokedRenderer(X, Y); + } + + this->m_Picker->Pick(X, Y, 0.0, this->CurrentRenderer); + ::vtkProp *prop = this->m_Picker->GetViewProp(); + + if (!prop) + return; + + this->Interaction = IDLE; + if (prop == m_AxesX) + this->Interaction = TRANS_X; + else if (prop == m_AxesY) + this->Interaction = TRANS_Y; + else if (prop == m_AxesZ) + this->Interaction = TRANS_Z; + else if (prop == m_RotX) + this->Interaction = ROT_X; + else if (prop == m_RotY) + this->Interaction = ROT_Y; + else if (prop == m_RotZ) + this->Interaction = ROT_Z; + else if (prop == m_ScaleX) + this->Interaction = SCALE_X; + else if (prop == m_ScaleY) + this->Interaction = SCALE_Y; + else if (prop == m_ScaleZ) + this->Interaction = SCALE_Z; + + if (this->Interaction != IDLE) { + this->StartEventPosition[0] = X; + this->StartEventPosition[1] = Y; + if (this->Prop3D) { + this->m_InitialTransform->SetMatrix(this->Prop3D->GetMatrix()); + } + this->EventCallbackCommand->SetAbortFlag(1); + this->InvokeEvent(::vtkCommand::StartInteractionEvent, nullptr); + this->Interactor->Render(); + } +} + +void vtkHandlerWidget::OnLeftButtonUp() { + if (this->Interaction == IDLE) + return; + + this->Interaction = IDLE; + this->InvokeEvent(::vtkCommand::EndInteractionEvent, nullptr); + this->Interactor->Render(); +} + +void vtkHandlerWidget::OnMouseMove() { + if (this->Interaction == IDLE || !this->Prop3D) + return; + + int X = this->Interactor->GetEventPosition()[0]; + int Y = this->Interactor->GetEventPosition()[1]; + + double dx = X - this->StartEventPosition[0]; + double dy = Y - this->StartEventPosition[1]; + + vtkSmartPointer<::vtkTransform> t = vtkSmartPointer<::vtkTransform>::New(); + t->PostMultiply(); + t->SetMatrix(this->m_InitialTransform->GetMatrix()); + + double factor = 0.01; + switch (this->Interaction) { + case TRANS_X: + t->Translate(dx * factor, 0, 0); + break; + case TRANS_Y: + t->Translate(0, dy * factor, 0); + break; + case TRANS_Z: + t->Translate(0, 0, dy * factor); + break; + case ROT_X: + t->RotateX(dy); + break; + case ROT_Y: + t->RotateY(dx); + break; + case ROT_Z: + t->RotateZ(dx); + break; + case SCALE_X: + t->Scale(std::max(0.1, 1.0 + dx * factor), 1.0, 1.0); + break; + case SCALE_Y: + t->Scale(1.0, std::max(0.1, 1.0 + dy * factor), 1.0); + break; + case SCALE_Z: + t->Scale(1.0, 1.0, std::max(0.1, 1.0 + dy * factor)); + break; + } + + this->Prop3D->SetUserMatrix(t->GetMatrix()); + this->UpdateGizmoPosition(); + + this->InvokeEvent(::vtkCommand::InteractionEvent, nullptr); + this->Interactor->Render(); +} + +void vtkHandlerWidget::PlaceWidget(double bounds[6]) { + (void)bounds; + this->UpdateGizmoPosition(); +} + +void vtkHandlerWidget::PlaceWidget() { this->UpdateGizmoPosition(); } + +void vtkHandlerWidget::SetTransform(::vtkTransform *t) { + if (!t || !this->Prop3D) + return; + this->Prop3D->SetUserMatrix(t->GetMatrix()); + this->UpdateGizmoPosition(); +} + +void vtkHandlerWidget::GetTransform(::vtkTransform *t) { + if (!t || !this->Prop3D) + return; + t->SetMatrix(this->Prop3D->GetUserMatrix()); +} + +void vtkHandlerWidget::CreateGizmos() { + auto create_arrow = [](double dir[3], double color[3]) { + auto arrow = vtkSmartPointer<::vtkArrowSource>::New(); + auto mapper = vtkSmartPointer<::vtkPolyDataMapper>::New(); + mapper->SetInputConnection(arrow->GetOutputPort()); + auto actor = vtkSmartPointer<::vtkActor>::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(color); + + auto t = vtkSmartPointer<::vtkTransform>::New(); + if (dir[1] > 0) + t->RotateZ(90); + else if (dir[2] > 0) + t->RotateY(-90); + actor->SetUserTransform(t); + return actor; + }; + + auto create_ring = [](int axis, double color[3]) { + auto arc = vtkSmartPointer<::vtkArcSource>::New(); + arc->SetCenter(0, 0, 0); + arc->SetResolution(64); + if (axis == 0) { + arc->SetPoint1(0, 1, 0); + arc->SetPoint2(0, -1, 0); + } else if (axis == 1) { + arc->SetPoint1(1, 0, 0); + arc->SetPoint2(-1, 0, 0); + } else if (axis == 2) { + arc->SetPoint1(1, 0, 0); + arc->SetPoint2(-1, 0, 0); + } + + auto mapper = vtkSmartPointer<::vtkPolyDataMapper>::New(); + mapper->SetInputConnection(arc->GetOutputPort()); + auto actor = vtkSmartPointer<::vtkActor>::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(color); + actor->GetProperty()->SetLineWidth(3); + return actor; + }; + + double red[] = {0.8, 0.1, 0.1}, green[] = {0.1, 0.8, 0.1}, + blue[] = {0.1, 0.1, 0.8}; + + double x[] = {1, 0, 0}, y[] = {0, 1, 0}, z[] = {0, 0, 1}; + m_AxesX = create_arrow(x, red); + m_AxesY = create_arrow(y, green); + m_AxesZ = create_arrow(z, blue); + + m_RotX = create_ring(0, red); + m_RotY = create_ring(1, green); + m_RotZ = create_ring(2, blue); + + auto create_cube = [](double pos[3], double color[3]) { + auto cube = vtkSmartPointer<::vtkCubeSource>::New(); + cube->SetCenter(pos[0], pos[1], pos[2]); + cube->SetXLength(0.12); + cube->SetYLength(0.12); + cube->SetZLength(0.12); + auto mapper = vtkSmartPointer<::vtkPolyDataMapper>::New(); + mapper->SetInputConnection(cube->GetOutputPort()); + auto actor = vtkSmartPointer<::vtkActor>::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(color); + return actor; + }; + + double px[] = {1.2, 0, 0}, py[] = {0, 1.2, 0}, pz[] = {0, 0, 1.2}; + m_ScaleX = create_cube(px, red); + m_ScaleY = create_cube(py, green); + m_ScaleZ = create_cube(pz, blue); +} + +void vtkHandlerWidget::UpdateGizmoPosition() { + if (!this->Prop3D) + return; + ::vtkMatrix4x4 *mat = this->Prop3D->GetMatrix(); + m_AxesX->SetUserMatrix(mat); + m_AxesY->SetUserMatrix(mat); + m_AxesZ->SetUserMatrix(mat); + m_RotX->SetUserMatrix(mat); + m_RotY->SetUserMatrix(mat); + m_RotZ->SetUserMatrix(mat); + m_ScaleX->SetUserMatrix(mat); + m_ScaleY->SetUserMatrix(mat); + m_ScaleZ->SetUserMatrix(mat); +} + +} // namespace Vtk +} // namespace uLib \ No newline at end of file diff --git a/src/Vtk/vtkHandlerWidget.h b/src/Vtk/vtkHandlerWidget.h new file mode 100644 index 0000000..7c048c6 --- /dev/null +++ b/src/Vtk/vtkHandlerWidget.h @@ -0,0 +1,111 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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. + +//////////////////////////////////////////////////////////////////////////////*/ + +#ifndef U_VTKHANDLERWIDGET_H +#define U_VTKHANDLERWIDGET_H + +#include "Math/Dense.h" +#include "uLibVtkInterface.h" + +#include +#include + +// Forward declarations of VTK classes in global namespace +class vtkActor; +class vtkCallbackCommand; +class vtkPropPicker; +class vtkTransform; +class vtkObject; +class vtkRenderWindowInteractor; + +namespace uLib { +namespace Vtk { + +/** + * @class vtkHandlerWidget + * @brief A Blender-like transform gizmo for move, rotate, and scale. + */ +class vtkHandlerWidget : public ::vtk3DWidget { +public: + static vtkHandlerWidget *New(); + vtkTypeMacro(vtkHandlerWidget, ::vtk3DWidget); + + vtkHandlerWidget(); + virtual ~vtkHandlerWidget(); + + virtual void SetEnabled(int enabling) override; + static void ProcessEvents(::vtkObject *caller, unsigned long event, + void *clientdata, void *calldata); + + void OnLeftButtonDown(); + void OnLeftButtonUp(); + void OnMouseMove(); + + enum InteractionState { + IDLE = 0, + TRANS_X, + TRANS_Y, + TRANS_Z, + ROT_X, + ROT_Y, + ROT_Z, + SCALE_X, + SCALE_Y, + SCALE_Z + }; + + using ::vtk3DWidget::PlaceWidget; + virtual void PlaceWidget(double bounds[6]) override; + virtual void PlaceWidget() override; + + // Transform handling // + void SetTransform(::vtkTransform *t); + void GetTransform(::vtkTransform *t); + +protected: + void CreateGizmos(); + void UpdateGizmoPosition(); + + int Interaction; + + // Visual components // + vtkSmartPointer<::vtkActor> m_AxesX, m_AxesY, m_AxesZ; // Arrows + vtkSmartPointer<::vtkActor> m_RotX, m_RotY, m_RotZ; // Rings + vtkSmartPointer<::vtkActor> m_ScaleX, m_ScaleY, m_ScaleZ; // Cubes + + vtkSmartPointer<::vtkPropPicker> m_Picker; + + double StartEventPosition[2]; + vtkSmartPointer<::vtkTransform> m_InitialTransform; + +private: + vtkHandlerWidget(const vtkHandlerWidget &) = delete; + void operator=(const vtkHandlerWidget &) = delete; +}; + +} // namespace Vtk +} // namespace uLib + +#endif // U_VTKHANDLERWIDGET_H