From 422113a0e9e903c34412b8b44252d9128083dbdf Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Wed, 25 Mar 2026 21:03:13 +0000 Subject: [PATCH] add vtk solids --- src/HEP/Geant/Solid.cpp | 4 + src/HEP/Geant/Solid.h | 3 + src/Math/QuadMesh.h | 2 + src/Math/TriangleMesh.h | 2 + src/Python/math_bindings.cpp | 8 +- src/Vtk/HEP/Geant/CMakeLists.txt | 4 + src/Vtk/HEP/Geant/testing/CMakeLists.txt | 1 + src/Vtk/HEP/Geant/testing/vtkSolidsTest.cpp | 84 +++++++++++++++++++++ src/Vtk/HEP/Geant/vtkBoxSolid.cpp | 57 ++++++++++++++ src/Vtk/HEP/Geant/vtkBoxSolid.h | 52 +++++++++++++ src/Vtk/HEP/Geant/vtkGeantScene.cpp | 17 ++++- src/Vtk/HEP/Geant/vtkGeantSolid.cpp | 11 ++- src/Vtk/HEP/Geant/vtkGeantSolid.h | 5 +- src/Vtk/HEP/Geant/vtkTessellatedSolid.cpp | 62 +++++++++++++++ src/Vtk/HEP/Geant/vtkTessellatedSolid.h | 38 ++++++++++ src/Vtk/uLibVtkInterface.cxx | 16 ++-- src/Vtk/uLibVtkInterface.h | 3 + 17 files changed, 353 insertions(+), 16 deletions(-) create mode 100644 src/Vtk/HEP/Geant/testing/vtkSolidsTest.cpp create mode 100644 src/Vtk/HEP/Geant/vtkBoxSolid.cpp create mode 100644 src/Vtk/HEP/Geant/vtkBoxSolid.h create mode 100644 src/Vtk/HEP/Geant/vtkTessellatedSolid.cpp create mode 100644 src/Vtk/HEP/Geant/vtkTessellatedSolid.h diff --git a/src/HEP/Geant/Solid.cpp b/src/HEP/Geant/Solid.cpp index cf78862..e5f5ab2 100644 --- a/src/HEP/Geant/Solid.cpp +++ b/src/HEP/Geant/Solid.cpp @@ -151,6 +151,7 @@ TessellatedSolid::TessellatedSolid(const char *name) } void TessellatedSolid::SetMesh(TriangleMesh &mesh) { + this->m_Mesh = mesh; G4TessellatedSolid *ts = this->m_Solid; for (int i = 0; i < mesh.Triangles().size(); ++i) { const Vector3i &trg = mesh.Triangles().at(i); @@ -165,6 +166,9 @@ void TessellatedSolid::SetMesh(TriangleMesh &mesh) { } } +void TessellatedSolid::Update() { +} + diff --git a/src/HEP/Geant/Solid.h b/src/HEP/Geant/Solid.h index 4837163..d05459b 100644 --- a/src/HEP/Geant/Solid.h +++ b/src/HEP/Geant/Solid.h @@ -93,11 +93,14 @@ public: void SetMesh(TriangleMesh &mesh); uLibGetMacro(Solid, G4TessellatedSolid *) virtual G4VSolid* GetG4Solid() const override { return (G4VSolid*)m_Solid; } + + const TriangleMesh& GetMesh() const { return m_Mesh; } public slots: void Update(); private : + TriangleMesh m_Mesh; G4TessellatedSolid *m_Solid; }; diff --git a/src/Math/QuadMesh.h b/src/Math/QuadMesh.h index b1a07a6..e98d5ce 100644 --- a/src/Math/QuadMesh.h +++ b/src/Math/QuadMesh.h @@ -52,7 +52,9 @@ public: Vector3f GetPoint(const Id_t id) const; inline std::vector & Points() { return this->m_Points; } + inline const std::vector & Points() const { return this->m_Points; } inline std::vector & Quads() { return this->m_Quads; } + inline const std::vector & Quads() const { return this->m_Quads; } const Vector4i & GetQuad(const Id_t id) const { return m_Quads.at(id); } Vector3f GetNormal(const Id_t id) const; diff --git a/src/Math/TriangleMesh.h b/src/Math/TriangleMesh.h index ecfa2d0..4acfe58 100644 --- a/src/Math/TriangleMesh.h +++ b/src/Math/TriangleMesh.h @@ -55,7 +55,9 @@ public: Vector3f GetPoint(const Id_t id) const; inline std::vector & Points() { return this->m_Points; } + inline const std::vector & Points() const { return this->m_Points; } inline std::vector & Triangles() { return this->m_Triangles; } + inline const std::vector & Triangles() const { return this->m_Triangles; } const Vector3i & GetTriangle(const Id_t id) const { return m_Triangles.at(id); } Vector3f GetNormal(const Id_t id) const; diff --git a/src/Python/math_bindings.cpp b/src/Python/math_bindings.cpp index f3f6b7c..9c6e6fe 100644 --- a/src/Python/math_bindings.cpp +++ b/src/Python/math_bindings.cpp @@ -432,9 +432,9 @@ void init_math(py::module_ &m) { .def("AddPoint", &TriangleMesh::AddPoint) .def("AddTriangle", py::overload_cast(&TriangleMesh::AddTriangle)) - .def("Points", &TriangleMesh::Points, + .def("Points", py::overload_cast<>(&TriangleMesh::Points), py::return_value_policy::reference_internal) - .def("Triangles", &TriangleMesh::Triangles, + .def("Triangles", py::overload_cast<>(&TriangleMesh::Triangles), py::return_value_policy::reference_internal) .def("GetTriangle", &TriangleMesh::GetTriangle) .def("GetNormal", &TriangleMesh::GetNormal); @@ -444,9 +444,9 @@ void init_math(py::module_ &m) { .def("AddPoint", &QuadMesh::AddPoint) .def("AddQuad", py::overload_cast(&QuadMesh::AddQuad)) - .def("Points", &QuadMesh::Points, + .def("Points", py::overload_cast<>(&QuadMesh::Points), py::return_value_policy::reference_internal) - .def("Quads", &QuadMesh::Quads, + .def("Quads", py::overload_cast<>(&QuadMesh::Quads), py::return_value_policy::reference_internal) .def("GetQuad", &QuadMesh::GetQuad) .def("GetNormal", &QuadMesh::GetNormal); diff --git a/src/Vtk/HEP/Geant/CMakeLists.txt b/src/Vtk/HEP/Geant/CMakeLists.txt index bf03459..a829345 100644 --- a/src/Vtk/HEP/Geant/CMakeLists.txt +++ b/src/Vtk/HEP/Geant/CMakeLists.txt @@ -6,6 +6,8 @@ set(HEP_GEANT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantSolid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/vtkBoxSolid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/vtkTessellatedSolid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantScene.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.cpp PARENT_SCOPE) @@ -13,6 +15,8 @@ set(HEP_GEANT_SOURCES set(HEP_GEANT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.h ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantSolid.h + ${CMAKE_CURRENT_SOURCE_DIR}/vtkBoxSolid.h + ${CMAKE_CURRENT_SOURCE_DIR}/vtkTessellatedSolid.h ${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantScene.h ${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.h PARENT_SCOPE) diff --git a/src/Vtk/HEP/Geant/testing/CMakeLists.txt b/src/Vtk/HEP/Geant/testing/CMakeLists.txt index 4cc85be..ee58f20 100644 --- a/src/Vtk/HEP/Geant/testing/CMakeLists.txt +++ b/src/Vtk/HEP/Geant/testing/CMakeLists.txt @@ -2,6 +2,7 @@ set(TESTS vtkGeantEventTest vtkGeantSceneTest + vtkSolidsTest vtkEmitterPrimaryTest vtkSkyPlaneEmitterPrimaryTest vtkCylinderEmitterPrimaryTest diff --git a/src/Vtk/HEP/Geant/testing/vtkSolidsTest.cpp b/src/Vtk/HEP/Geant/testing/vtkSolidsTest.cpp new file mode 100644 index 0000000..435b352 --- /dev/null +++ b/src/Vtk/HEP/Geant/testing/vtkSolidsTest.cpp @@ -0,0 +1,84 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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/HEP/Geant/vtkBoxSolid.h" +#include "Vtk/HEP/Geant/vtkTessellatedSolid.h" +#include "Vtk/uLibVtkViewer.h" +#include "HEP/Geant/Solid.h" +#include "Math/ContainerBox.h" +#include "Math/TriangleMesh.h" +#include "Math/Units.h" + +#include +#include + +using namespace uLib; + +int main(int argc, char** argv) { + bool interactive = (argc > 1 && std::string(argv[1]) == "-i"); + + // 1. Create a BoxSolid + ContainerBox box; + box.Scale(Vector3f(1_m, 2_m, 3_m)); + Geant::BoxSolid gBox("MyBox", &box); + gBox.Update(); + + Vtk::vtkBoxSolid vtkBox(&gBox); + + // 2. Create a TessellatedSolid + Geant::TessellatedSolid gTess("MyTess"); + TriangleMesh mesh; + // Create a simple pyramid + mesh.Points().push_back(Vector3f(0, 0, 1_m)); // apex + mesh.Points().push_back(Vector3f(-1_m, -1_m, 0)); + mesh.Points().push_back(Vector3f( 1_m, -1_m, 0)); + mesh.Points().push_back(Vector3f( 1_m, 1_m, 0)); + mesh.Points().push_back(Vector3f(-1_m, 1_m, 0)); + + mesh.Triangles().push_back(Vector3i(1, 2, 0)); + mesh.Triangles().push_back(Vector3i(2, 3, 0)); + mesh.Triangles().push_back(Vector3i(3, 4, 0)); + mesh.Triangles().push_back(Vector3i(4, 1, 0)); + mesh.Triangles().push_back(Vector3i(1, 3, 2)); // base + mesh.Triangles().push_back(Vector3i(1, 4, 3)); // base + + gTess.SetMesh(mesh); + gTess.Update(); + + Vtk::vtkTessellatedSolid vtkTess(&gTess); + + // 3. Visualization setup + Vtk::Viewer viewer; + vtkBox.AddToViewer(viewer); + vtkTess.AddToViewer(viewer); + + // Color them differently + vtkActor::SafeDownCast(vtkBox.GetProp())->GetProperty()->SetColor(0.8, 0.2, 0.2); // Redish box + vtkActor::SafeDownCast(vtkTess.GetProp())->GetProperty()->SetColor(0.2, 0.8, 0.2); // Greenish tess + + // Position tessellated solid away from box + Matrix4f trans = Matrix4f::Identity(); + trans.block<3,1>(0,3) = Vector3f(5_m, 0, 0); + gTess.SetTransform(trans); + vtkTess.Update(); + + std::cout << "..:: Testing vtkSolidsTest ::.." << std::endl; + std::cout << "Box and Tessellated solids initialized." << std::endl; + + if (interactive) { + viewer.ZoomAuto(); + viewer.Start(); + } else { + std::cout << "Non-interactive test passed." << std::endl; + } + + return 0; +} diff --git a/src/Vtk/HEP/Geant/vtkBoxSolid.cpp b/src/Vtk/HEP/Geant/vtkBoxSolid.cpp new file mode 100644 index 0000000..1626737 --- /dev/null +++ b/src/Vtk/HEP/Geant/vtkBoxSolid.cpp @@ -0,0 +1,57 @@ +/*////////////////////////////////////////////////////////////////////////////// +// CMT Cosmic Muon Tomography project ////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2014, Universita' degli Studi Padova, INFN sez. di Padova + All rights reserved + + Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > + +//////////////////////////////////////////////////////////////////////////////*/ + +#include "vtkBoxSolid.h" +#include +#include +#include + +namespace uLib { +namespace Vtk { + +vtkBoxSolid::vtkBoxSolid(Geant::BoxSolid *content) + : vtkGeantSolid(content), m_BoxContent(content) { + // Re-run Update for box-specific pipe + this->Update(); +} + +vtkBoxSolid::~vtkBoxSolid() {} + +void vtkBoxSolid::Update() { + this->UpdateGeometry(); + this->UpdateTransform(); +} + +void vtkBoxSolid::UpdateGeometry() { + if (!m_BoxContent || !m_BoxContent->GetObject()) { + // Fallback to base tessellation if no model object + vtkGeantSolid::UpdateGeometry(); + return; + } + + // Use the underlying ContainerBox for precise geometry + Vector3f size = m_BoxContent->GetObject()->GetSize(); + + vtkNew cube; + cube->SetXLength(size(0)); + cube->SetYLength(size(1)); + cube->SetZLength(size(2)); + cube->Update(); + + vtkPolyData *poly = GetPolyData(); + if (poly) { + poly->ShallowCopy(cube->GetOutput()); + poly->Modified(); + } +} + +} // namespace Vtk +} // namespace uLib diff --git a/src/Vtk/HEP/Geant/vtkBoxSolid.h b/src/Vtk/HEP/Geant/vtkBoxSolid.h new file mode 100644 index 0000000..7df7715 --- /dev/null +++ b/src/Vtk/HEP/Geant/vtkBoxSolid.h @@ -0,0 +1,52 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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_VTKBOXSOLID_H +#define U_VTKBOXSOLID_H + +#include "vtkGeantSolid.h" + +namespace uLib { +namespace Vtk { + +/** + * @brief VTK Puppet for visualizing a Geant::BoxSolid. + */ +class vtkBoxSolid : public vtkGeantSolid { +public: + vtkBoxSolid(Geant::BoxSolid *content); + virtual ~vtkBoxSolid(); + + virtual void Update() override; + virtual void UpdateGeometry() override; + +protected: + Geant::BoxSolid *m_BoxContent; +}; + +} // namespace Vtk +} // namespace uLib + +#endif // U_VTKBOXSOLID_H diff --git a/src/Vtk/HEP/Geant/vtkGeantScene.cpp b/src/Vtk/HEP/Geant/vtkGeantScene.cpp index 75e3c94..905f03b 100644 --- a/src/Vtk/HEP/Geant/vtkGeantScene.cpp +++ b/src/Vtk/HEP/Geant/vtkGeantScene.cpp @@ -25,6 +25,8 @@ #include "vtkGeantScene.h" #include "vtkGeantSolid.h" +#include "vtkBoxSolid.h" +#include "vtkTessellatedSolid.h" #include "Vtk/vtkViewport.h" namespace uLib { @@ -54,8 +56,19 @@ vtkGeantScene::vtkGeantScene(Geant::Scene *scene) // Only create a puppet if the solid has a valid G4VSolid if (solid->GetG4Solid()) { - vtkGeantSolid *vtkSolid = new vtkGeantSolid(solid); - m_SolidPuppets.push_back(vtkSolid); + vtkGeantSolid *vtkSolid = nullptr; + if (auto *box = dynamic_cast(solid)) { + vtkSolid = new vtkBoxSolid(box); + } else if (auto *tess = dynamic_cast(solid)) { + vtkSolid = new vtkTessellatedSolid(tess); + } else { + vtkSolid = new vtkGeantSolid(solid); + vtkSolid->Update(); + } + + if (vtkSolid) { + m_SolidPuppets.push_back(vtkSolid); + } } } } diff --git a/src/Vtk/HEP/Geant/vtkGeantSolid.cpp b/src/Vtk/HEP/Geant/vtkGeantSolid.cpp index df0b2d1..bd0e544 100644 --- a/src/Vtk/HEP/Geant/vtkGeantSolid.cpp +++ b/src/Vtk/HEP/Geant/vtkGeantSolid.cpp @@ -45,7 +45,6 @@ namespace Vtk { vtkGeantSolid::vtkGeantSolid(Content *content) : m_SolidActor(vtkActor::New()), m_Content(content) { this->InstallPipe(); - this->Update(); } vtkGeantSolid::~vtkGeantSolid() { @@ -59,6 +58,11 @@ vtkPolyData *vtkGeantSolid::GetPolyData() const { } void vtkGeantSolid::Update() { + this->UpdateGeometry(); + this->UpdateTransform(); +} + +void vtkGeantSolid::UpdateGeometry() { if (!m_Content) return; @@ -103,6 +107,11 @@ void vtkGeantSolid::Update() { polyData->SetPolys(polys); polyData->Modified(); } +} + +void vtkGeantSolid::UpdateTransform() { + if (!m_Content || !m_SolidActor) + return; // Apply the Geant4 transform (position/rotation) if placed if (m_Content->GetPhysical()) { diff --git a/src/Vtk/HEP/Geant/vtkGeantSolid.h b/src/Vtk/HEP/Geant/vtkGeantSolid.h index 8a947ca..8fb127d 100644 --- a/src/Vtk/HEP/Geant/vtkGeantSolid.h +++ b/src/Vtk/HEP/Geant/vtkGeantSolid.h @@ -51,7 +51,10 @@ public: virtual class vtkPolyData *GetPolyData() const override; - virtual void Update(); + virtual void Update() override; + + virtual void UpdateGeometry(); + virtual void UpdateTransform(); protected: virtual void InstallPipe(); diff --git a/src/Vtk/HEP/Geant/vtkTessellatedSolid.cpp b/src/Vtk/HEP/Geant/vtkTessellatedSolid.cpp new file mode 100644 index 0000000..f4b59fd --- /dev/null +++ b/src/Vtk/HEP/Geant/vtkTessellatedSolid.cpp @@ -0,0 +1,62 @@ +/*////////////////////////////////////////////////////////////////////////////// +// CMT Cosmic Muon Tomography project ////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2014, Universita' degli Studi Padova, INFN sez. di Padova + All rights reserved + + Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > + +//////////////////////////////////////////////////////////////////////////////*/ + +#include "vtkTessellatedSolid.h" + +#include +#include +#include + +namespace uLib { +namespace Vtk { + +vtkTessellatedSolid::vtkTessellatedSolid(Geant::TessellatedSolid *content) + : vtkGeantSolid(content), m_TessContent(content) { + this->Update(); +} + +vtkTessellatedSolid::~vtkTessellatedSolid() {} + +void vtkTessellatedSolid::Update() { + this->UpdateGeometry(); + this->UpdateTransform(); +} + +void vtkTessellatedSolid::UpdateGeometry() { + if (!m_TessContent || m_TessContent->GetMesh().Points().empty()) { + // Fallback to base tessellation if no model mesh + vtkGeantSolid::UpdateGeometry(); + return; + } + + const TriangleMesh &mesh = m_TessContent->GetMesh(); + + vtkNew points; + for (const auto& pt : mesh.Points()) { + points->InsertNextPoint(pt(0), pt(1), pt(2)); + } + + vtkNew polys; + for (const auto& trg : mesh.Triangles()) { + vtkIdType ids[3] = { (vtkIdType)trg(0), (vtkIdType)trg(1), (vtkIdType)trg(2) }; + polys->InsertNextCell(3, ids); + } + + vtkPolyData *poly = GetPolyData(); + if (poly) { + poly->SetPoints(points); + poly->SetPolys(polys); + poly->Modified(); + } +} + +} // namespace Vtk +} // namespace uLib diff --git a/src/Vtk/HEP/Geant/vtkTessellatedSolid.h b/src/Vtk/HEP/Geant/vtkTessellatedSolid.h new file mode 100644 index 0000000..a24a850 --- /dev/null +++ b/src/Vtk/HEP/Geant/vtkTessellatedSolid.h @@ -0,0 +1,38 @@ +/*////////////////////////////////////////////////////////////////////////////// +// 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 > + +//////////////////////////////////////////////////////////////////////////////*/ + +#ifndef U_VTKTESSELLATEDSOLID_H +#define U_VTKTESSELLATEDSOLID_H + +#include "vtkGeantSolid.h" + +namespace uLib { +namespace Vtk { + +/** + * @brief VTK Puppet for visualizing a Geant::TessellatedSolid. + */ +class vtkTessellatedSolid : public vtkGeantSolid { +public: + vtkTessellatedSolid(Geant::TessellatedSolid *content); + virtual ~vtkTessellatedSolid(); + + virtual void Update() override; + virtual void UpdateGeometry() override; + +protected: + Geant::TessellatedSolid *m_TessContent; +}; + +} // namespace Vtk +} // namespace uLib + +#endif // U_VTKTESSELLATEDSOLID_H diff --git a/src/Vtk/uLibVtkInterface.cxx b/src/Vtk/uLibVtkInterface.cxx index a181c45..8ce675d 100644 --- a/src/Vtk/uLibVtkInterface.cxx +++ b/src/Vtk/uLibVtkInterface.cxx @@ -39,11 +39,11 @@ #include #include -#include -#include -#include - +#include "vtkViewport.h" +#include "uLibVtkInterface.h" #include +#include +#include #include #include #include @@ -278,14 +278,14 @@ void Puppet::DisconnectRenderer(vtkRenderer *renderer) } } -void Puppet::ConnectViewer(Viewer *viewer) +void Puppet::AddToViewer(Viewport &viewer) { - // TODO + viewer.AddPuppet(*this); } -void Puppet::DisonnectViewer(Viewer *viewer) +void Puppet::RemoveFromViewer(Viewport &viewer) { - // TODO + viewer.RemovePuppet(*this); } vtkRendererCollection *Puppet::GetRenderers() const diff --git a/src/Vtk/uLibVtkInterface.h b/src/Vtk/uLibVtkInterface.h index 8595854..66cff0e 100644 --- a/src/Vtk/uLibVtkInterface.h +++ b/src/Vtk/uLibVtkInterface.h @@ -107,6 +107,9 @@ public: virtual void ConnectInteractor(class vtkRenderWindowInteractor *interactor); + void AddToViewer(class Viewport &viewer); + void RemoveFromViewer(class Viewport &viewer); + protected: void SetProp(vtkProp *prop);