From 6234dffaa740b47f14e777b85cee6dff16b2db46 Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Thu, 19 Mar 2026 16:39:05 +0000 Subject: [PATCH] add voximage represetation and test --- src/Vtk/Math/testing/CMakeLists.txt | 1 + .../testing/vtkVoxImageInteractiveTest.cpp | 129 ++++++++++++++++++ src/Vtk/Math/vtkVoxImage.cpp | 26 +++- src/Vtk/Math/vtkVoxImage.h | 3 + 4 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp diff --git a/src/Vtk/Math/testing/CMakeLists.txt b/src/Vtk/Math/testing/CMakeLists.txt index aae16bb..db5a1a4 100644 --- a/src/Vtk/Math/testing/CMakeLists.txt +++ b/src/Vtk/Math/testing/CMakeLists.txt @@ -4,6 +4,7 @@ set(TESTS vtkTriangleMeshTest vtkQuadMeshTest vtkVoxImageTest + vtkVoxImageInteractiveTest ) set(LIBRARIES diff --git a/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp b/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp new file mode 100644 index 0000000..42d6bfc --- /dev/null +++ b/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp @@ -0,0 +1,129 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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 "Vtk/Math/vtkVoxImage.h" +#include "Math/VoxImage.h" +#include "Vtk/uLibVtkViewer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uLib; + +struct AppState { + std::vector images; + Vtk::Viewer* viewer; +}; + +void KeyPressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) { + auto* interactor = static_cast(caller); + auto* state = static_cast(clientData); + + std::string key = interactor->GetKeySym(); + if (key == "w") { + std::cout << "--> Switching all images to Wireframe Box" << std::endl; + for (auto* img : state->images) img->SetRepresentation(Vtk::Puppet::Wireframe); + state->viewer->GetRenderWindow()->Render(); + } + else if (key == "s") { + std::cout << "--> Switching all images to Surface (Volume Rendering)" << std::endl; + for (auto* img : state->images) img->SetRepresentation(Vtk::Puppet::Surface); + state->viewer->GetRenderWindow()->Render(); + } +} + +int main(int argc, char** argv) { + float factor = 1.0e6f; + + // --- Image 1: Spherical Shell --- + Vector3i dims1(64, 64, 64); + VoxImage img1(dims1); + img1.SetSpacing(Vector3f(1.0, 1.0, 1.0)); + img1.SetPosition(Vector3f(-40, -32, -32)); + + for (int z = 0; z < dims1(2); ++z) { + for (int y = 0; y < dims1(1); ++y) { + for (int x = 0; x < dims1(0); ++x) { + float dx = x - 32.0f; + float dy = y - 32.0f; + float dz = z - 32.0f; + float dist = std::sqrt(dx*dx + dy*dy + dz*dz); + Voxel v; + if (dist < 25.0f && dist > 10.0f) { + v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor; + } else { + v.Value = 0.0f; + } + img1[Vector3i(x, y, z)] = v; + } + } + } + + // --- Image 2: Axes Gradient --- + Vector3i dims2(64, 64, 64); + VoxImage img2(dims2); + img2.SetSpacing(Vector3f(1.0, 1.0, 1.0)); + img2.SetPosition(Vector3f(40, -32, -32)); + + for (int z = 0; z < dims2(2); ++z) { + for (int y = 0; y < dims2(1); ++y) { + for (int x = 0; x < dims2(0); ++x) { + Voxel v; + // Linear gradient along X, Y, Z + float val = (float(x)/dims2(0) + float(y)/dims2(1) + float(z)/dims2(2)) / 3.0f; + v.Value = (40.0f * val) / factor; + img2[Vector3i(x, y, z)] = v; + } + } + } + + Vtk::vtkVoxImage vtk_img1(img1); + vtk_img1.setShadingPreset(0); + + Vtk::vtkVoxImage vtk_img2(img2); + vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety + + Vtk::Viewer viewer; + viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1); + viewer.AddPuppet(vtk_img1); + viewer.AddPuppet(vtk_img2); + + // Setup KeyPress Callback + AppState state; + state.images.push_back(&vtk_img1); + state.images.push_back(&vtk_img2); + state.viewer = &viewer; + + vtkSmartPointer keyCallback = vtkSmartPointer::New(); + keyCallback->SetCallback(KeyPressCallbackFunction); + keyCallback->SetClientData(&state); + viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback); + + std::cout << "=========================================" << std::endl; + std::cout << " vtkVoxImage Interactive Viewer Test" << std::endl; + std::cout << " [LEFT] Spherical Shell (MIP)" << std::endl; + std::cout << " [RIGHT] Axes Gradient (Composite)" << std::endl; + std::cout << "-----------------------------------------" << std::endl; + std::cout << " Press [w] to show Wireframe Bounding Boxes" << std::endl; + std::cout << " Press [s] to switch back to Volume Rendering" << std::endl; + std::cout << " Press [q] to quit" << std::endl; + std::cout << "=========================================" << std::endl; + + viewer.ZoomAuto(); + viewer.Start(); + + return 0; +} diff --git a/src/Vtk/Math/vtkVoxImage.cpp b/src/Vtk/Math/vtkVoxImage.cpp index 6d82741..3d36d74 100644 --- a/src/Vtk/Math/vtkVoxImage.cpp +++ b/src/Vtk/Math/vtkVoxImage.cpp @@ -125,6 +125,7 @@ void vtkVoxImage::SetContent() { vtkVoxImage::vtkVoxImage(Content &content) : m_Content(content), m_Actor(vtkVolume::New()), m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()), + m_OutlineActor(vtkActor::New()), m_Reader(NULL), m_Writer(NULL), writer_factor(1.E6) { GetContent(); InstallPipe(); @@ -134,6 +135,7 @@ vtkVoxImage::~vtkVoxImage() { m_Image->Delete(); m_Actor->Delete(); m_Outline->Delete(); + m_OutlineActor->Delete(); } vtkImageData *vtkVoxImage::GetImageData() { @@ -260,6 +262,18 @@ void vtkVoxImage::setShadingPreset(int blendType) { } } +void vtkVoxImage::SetRepresentation(Representation mode) { + if (mode == Wireframe) { + m_Actor->SetVisibility(0); + m_OutlineActor->SetVisibility(1); + } else if (mode == Surface) { + m_Actor->SetVisibility(1); + m_OutlineActor->SetVisibility(0); + } else { + Puppet::SetRepresentation(mode); + } +} + void vtkVoxImage::Update() { m_Actor->Update(); m_Outline->SetBounds(m_Image->GetBounds()); @@ -284,12 +298,16 @@ void vtkVoxImage::InstallPipe() { vtkSmartPointer mmapper = vtkSmartPointer::New(); mmapper->SetInputConnection(m_Outline->GetOutputPort()); - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mmapper); - actor->GetProperty()->SetRepresentationToWireframe(); - actor->GetProperty()->SetAmbient(0.7); + + m_OutlineActor->SetMapper(mmapper); + m_OutlineActor->GetProperty()->SetRepresentationToWireframe(); + m_OutlineActor->GetProperty()->SetAmbient(0.7); this->SetProp(m_Actor); + this->SetProp(m_OutlineActor); + + // Default look + this->SetRepresentation(Surface); } } // namespace Vtk diff --git a/src/Vtk/Math/vtkVoxImage.h b/src/Vtk/Math/vtkVoxImage.h index 5cfd65c..7eb9ba4 100644 --- a/src/Vtk/Math/vtkVoxImage.h +++ b/src/Vtk/Math/vtkVoxImage.h @@ -37,6 +37,7 @@ #include "Vtk/uLibVtkInterface.h" class vtkImageData; +class vtkActor; namespace uLib { namespace Vtk { @@ -62,6 +63,7 @@ public: void ReadFromXMLFile(const char *fname); void setShadingPreset(int blendType = 2); + void SetRepresentation(Representation mode); void Update(); @@ -73,6 +75,7 @@ private: vtkVolume *m_Actor; vtkImageData *m_Image; vtkCubeSource *m_Outline; + vtkActor *m_OutlineActor; vtkXMLImageDataReader *m_Reader; vtkXMLImageDataWriter *m_Writer;