add vtk geant solid and scene

This commit is contained in:
AndreaRigoni
2026-03-25 18:47:52 +00:00
parent 7d4acaef6d
commit 6a65fe94c8
15 changed files with 523 additions and 26 deletions

View File

@@ -102,6 +102,7 @@ void Scene::AddSolid(Solid *solid, Solid *parent) {
const Solid* Scene::GetWorld() const { return d->m_World; }
ContainerBox* Scene::GetWorldBox() const { return &d->m_WorldBox; }
const Vector<Solid*>& Scene::GetSolids() const { return d->m_Solids; }
void Scene::ConstructWorldBox(const Vector3f &size, const char *material) {
d->m_WorldBox.Scale(size);

View File

@@ -58,6 +58,9 @@ public:
ContainerBox* GetWorldBox() const;
/// Get the list of solids in the scene
const Vector<Solid*>& GetSolids() const;
/// Set the primary generator (emitter) for the simulation.
/// The Scene does NOT take ownership of the emitter.
void SetEmitter(EmitterPrimary *emitter);

View File

@@ -5,11 +5,15 @@
set(HEP_GEANT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantSolid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantScene.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.cpp
PARENT_SCOPE)
set(HEP_GEANT_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantSolid.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantScene.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.h
PARENT_SCOPE)

View File

@@ -1,6 +1,7 @@
# TESTS
set(TESTS
vtkGeantEventTest
vtkGeantSceneTest
vtkEmitterPrimaryTest
vtkSkyPlaneEmitterPrimaryTest
vtkCylinderEmitterPrimaryTest

View File

@@ -0,0 +1,65 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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 "Geant/Solid.h"
#include "HEP/Geant/Scene.h"
#include "Math/ContainerBox.h"
#include "Math/Dense.h"
#include "Math/Units.h"
#include "Vtk/uLibVtkViewer.h"
#include "Vtk/HEP/Geant/vtkGeantScene.h"
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <iostream>
using namespace uLib;
int main(int argc, char** argv) {
bool interactive = (argc > 1 && std::string(argv[1]) == "-i");
// 1. Setup Geant4 Scene
Geant::Scene scene;
scene.ConstructWorldBox(Vector3f(30_m, 30_m, 30_m), "G4_AIR");
// Add an iron cube inside the world
ContainerBox iron_box;
iron_box.Scale(Vector3f(10_m, 10_m, 10_m));
iron_box.SetPosition(Vector3f(-5_m, -5_m, -5_m));
Geant::BoxSolid* iron_cube = new Geant::BoxSolid("IronCube", &iron_box);
iron_cube->SetNistMaterial("G4_Fe");
iron_cube->Update();
scene.AddSolid(iron_cube);
scene.Initialize();
// 2. Build VTK scene representation
Vtk::Viewer viewer;
viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1);
Vtk::vtkGeantScene vtkScene(&scene);
vtkScene.AddToViewer(viewer);
std::cout << "==================================================" << std::endl;
std::cout << " vtkGeantScene Test" << std::endl;
std::cout << " World box + 1 iron cube displayed" << std::endl;
std::cout << "==================================================" << std::endl;
if (interactive) {
viewer.ZoomAuto();
viewer.Start();
} else {
std::cout << "Non-interactive test: scene initialized successfully" << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,89 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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 "vtkGeantScene.h"
#include "vtkGeantSolid.h"
#include "Vtk/vtkViewport.h"
namespace uLib {
namespace Vtk {
vtkGeantScene::vtkGeantScene(Geant::Scene *scene)
: m_Scene(scene), m_WorldPuppet(nullptr) {
if (!m_Scene)
return;
// 1. Create the world box wireframe puppet
ContainerBox *worldBox = m_Scene->GetWorldBox();
if (worldBox) {
m_WorldPuppet = new vtkContainerBox(worldBox);
m_WorldPuppet->SetRepresentation(Puppet::Wireframe);
m_WorldPuppet->ShowScaleMeasures(true);
}
// 2. Create puppets for each non-world solid
const Geant::Solid *world = m_Scene->GetWorld();
const Vector<Geant::Solid *> &solids = m_Scene->GetSolids();
for (Geant::Solid *solid : solids) {
// Skip the world volume itself — it's already shown as the wireframe box
if (solid == world)
continue;
// Only create a puppet if the solid has a valid G4VSolid
if (solid->GetG4Solid()) {
vtkGeantSolid *vtkSolid = new vtkGeantSolid(solid);
m_SolidPuppets.push_back(vtkSolid);
}
}
}
vtkGeantScene::~vtkGeantScene() {
delete m_WorldPuppet;
for (auto *p : m_SolidPuppets) {
delete p;
}
}
void vtkGeantScene::AddToViewer(Viewport &viewer) {
if (m_WorldPuppet) {
viewer.AddPuppet(*m_WorldPuppet);
}
for (auto *p : m_SolidPuppets) {
viewer.AddPuppet(*p);
}
}
void vtkGeantScene::RemoveFromViewer(Viewport &viewer) {
if (m_WorldPuppet) {
viewer.RemovePuppet(*m_WorldPuppet);
}
for (auto *p : m_SolidPuppets) {
viewer.RemovePuppet(*p);
}
}
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,87 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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_VTKGEANTSCENE_H
#define U_VTKGEANTSCENE_H
#include "HEP/Geant/Scene.h"
#include "uLibVtkInterface.h"
#include "Vtk/Math/vtkContainerBox.h"
#include <vector>
#include <memory>
namespace uLib {
namespace Vtk {
class vtkGeantSolid;
/**
* @brief VTK Puppet representing the entire Geant::Scene.
*
* When constructed, it creates child puppets for the world box (as a
* vtkContainerBox wireframe) and for each non-world Solid in the scene
* (as vtkGeantSolid surfaces).
*
* Usage:
* @code
* Geant::Scene scene;
* scene.ConstructWorldBox(Vector3f(30_m, 30_m, 30_m), "G4_AIR");
* // ... add solids ...
* scene.Initialize();
*
* Vtk::Viewer viewer;
* Vtk::vtkGeantScene vtkScene(&scene);
* vtkScene.AddToViewer(viewer);
* viewer.Start();
* @endcode
*/
class vtkGeantScene : public Object {
public:
vtkGeantScene(Geant::Scene *scene);
~vtkGeantScene();
/// Add all puppets (world box + solids) to a viewer.
void AddToViewer(class Viewport &viewer);
/// Remove all puppets from viewport.
void RemoveFromViewer(class Viewport &viewer);
/// Get the world box puppet
vtkContainerBox* GetWorldPuppet() const { return m_WorldPuppet; }
/// Get the solid puppets
const std::vector<vtkGeantSolid*>& GetSolidPuppets() const { return m_SolidPuppets; }
private:
Geant::Scene *m_Scene;
vtkContainerBox *m_WorldPuppet;
std::vector<vtkGeantSolid*> m_SolidPuppets;
};
} // namespace Vtk
} // namespace uLib
#endif // U_VTKGEANTSCENE_H

View File

@@ -0,0 +1,156 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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 "vtkGeantSolid.h"
#include <vtkActor.h>
#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include <vtkMatrix4x4.h>
#include <Geant4/G4VSolid.hh>
#include <Geant4/G4Polyhedron.hh>
#include <Geant4/G4VPhysicalVolume.hh>
namespace uLib {
namespace Vtk {
vtkGeantSolid::vtkGeantSolid(Content *content)
: m_SolidActor(vtkActor::New()), m_Content(content) {
this->InstallPipe();
this->Update();
}
vtkGeantSolid::~vtkGeantSolid() {
m_SolidActor->Delete();
}
vtkPolyData *vtkGeantSolid::GetPolyData() const {
if (!m_SolidActor || !m_SolidActor->GetMapper())
return NULL;
return vtkPolyData::SafeDownCast(m_SolidActor->GetMapper()->GetInput());
}
void vtkGeantSolid::Update() {
if (!m_Content)
return;
G4VSolid *g4solid = m_Content->GetG4Solid();
if (!g4solid)
return;
// Get the polyhedron tessellation from Geant4
G4Polyhedron *polyhedron = g4solid->GetPolyhedron();
if (!polyhedron)
return;
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
// Extract vertices
int nVertices = polyhedron->GetNoVertices();
for (int i = 1; i <= nVertices; ++i) {
G4Point3D vtx = polyhedron->GetVertex(i);
points->InsertNextPoint(vtx.x(), vtx.y(), vtx.z());
}
// Extract facets (polygons)
int nFacets = polyhedron->GetNoFacets();
for (int f = 1; f <= nFacets; ++f) {
G4int nEdges;
G4int iVertex[4]; // G4Polyhedron facets have at most 4 vertices
// GetNextFacet returns edges; for quads nEdges=4, for triangles nEdges=3
polyhedron->GetFacet(f, nEdges, iVertex);
vtkIdType ids[4];
for (int e = 0; e < nEdges; ++e) {
// G4Polyhedron vertices are 1-indexed; VTK expects 0-indexed
ids[e] = static_cast<vtkIdType>(std::abs(iVertex[e]) - 1);
}
polys->InsertNextCell(nEdges, ids);
}
vtkPolyData *polyData = GetPolyData();
if (polyData) {
polyData->SetPoints(points);
polyData->SetPolys(polys);
polyData->Modified();
}
// Apply the Geant4 transform (position/rotation) if placed
if (m_Content->GetPhysical()) {
auto *phys = m_Content->GetPhysical();
G4ThreeVector pos = phys->GetTranslation();
const G4RotationMatrix *rot = phys->GetRotation();
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
transform->Identity();
transform->Translate(pos.x(), pos.y(), pos.z());
if (rot) {
// G4RotationMatrix stores the inverse of the rotation for placement
G4RotationMatrix invRot = rot->inverse();
double elements[16] = {
invRot.xx(), invRot.xy(), invRot.xz(), 0,
invRot.yx(), invRot.yy(), invRot.yz(), 0,
invRot.zx(), invRot.zy(), invRot.zz(), 0,
0, 0, 0, 1
};
vtkSmartPointer<vtkMatrix4x4> mat = vtkSmartPointer<vtkMatrix4x4>::New();
mat->DeepCopy(elements);
transform->Concatenate(mat);
}
m_SolidActor->SetUserTransform(transform);
}
}
void vtkGeantSolid::InstallPipe() {
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(polyData);
m_SolidActor->SetMapper(mapper);
// Default look: semi-transparent blue surface
m_SolidActor->GetProperty()->SetColor(0.4, 0.6, 0.9);
m_SolidActor->GetProperty()->SetOpacity(0.3);
m_SolidActor->GetProperty()->SetAmbient(0.5);
m_SolidActor->GetProperty()->SetDiffuse(0.6);
m_SolidActor->GetProperty()->SetSpecular(0.2);
m_SolidActor->GetProperty()->SetEdgeVisibility(1);
m_SolidActor->GetProperty()->SetEdgeColor(0.2, 0.3, 0.5);
this->SetProp(m_SolidActor);
}
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,66 @@
/*//////////////////////////////////////////////////////////////////////////////
// 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_VTKGEANTSOLID_H
#define U_VTKGEANTSOLID_H
#include "HEP/Geant/Solid.h"
#include "uLibVtkInterface.h"
#include "vtkPolydata.h"
class vtkActor;
namespace uLib {
namespace Vtk {
/**
* @brief VTK Puppet for visualizing a Geant::Solid.
*
* Renders the G4VSolid geometry as a tessellated polydata surface.
* Works with BoxSolid, TessellatedSolid, or any Solid that provides
* a valid G4VSolid via GetG4Solid().
*/
class vtkGeantSolid : public Puppet, public Polydata {
typedef Geant::Solid Content;
public:
vtkGeantSolid(Content *content);
~vtkGeantSolid();
virtual class vtkPolyData *GetPolyData() const override;
virtual void Update();
protected:
virtual void InstallPipe();
vtkActor *m_SolidActor;
Content *m_Content;
};
} // namespace Vtk
} // namespace uLib
#endif // U_VTKGEANTSOLID_H

View File

@@ -48,13 +48,11 @@ namespace uLib {
namespace Vtk {
struct ContainerBoxData {
vtkActor *m_Cube;
vtkActor *m_Axes;
vtkSmartPointer<vtkActor> m_Cube;
vtkSmartPointer<vtkActor> m_Axes;
ContainerBoxData() : m_Cube(vtkActor::New()), m_Axes(vtkActor::New()) {}
ContainerBoxData() : m_Cube(vtkSmartPointer<vtkActor>::New()), m_Axes(vtkSmartPointer<vtkActor>::New()) {}
~ContainerBoxData() {
m_Cube->Delete();
m_Axes->Delete();
}
};

View File

@@ -46,13 +46,14 @@ int main() {
box.Scale(Vector3f(2.0, 3.0, 4.0));
box.SetPosition(Vector3f(1.0, 1.0, 1.0));
// 3. Setup the Viewer
Vtk::Viewer viewer;
// 2. Wrap it in a Vtk::vtkContainerBox (Vtk Puppet)
Vtk::vtkContainerBox v_box(&box);
v_box.SetRepresentation(Vtk::Puppet::Surface);
v_box.SetOpacity(0.5);
// 3. Setup the Viewer
Vtk::Viewer viewer;
viewer.AddPuppet(v_box);
// 4. Create and setup the vtkHandlerWidget
@@ -112,5 +113,6 @@ int main() {
<< std::endl;
}
handler->EnabledOff();
END_TESTING;
}

View File

@@ -84,6 +84,13 @@ Viewer::Viewer()
}
Viewer::~Viewer() {
this->DisableHandler();
if (this->GetRenderWindow()) {
this->GetRenderWindow()->RemoveAllObservers();
}
if (this->GetInteractor()) {
this->GetInteractor()->RemoveAllObservers();
}
UninstallPipe();
delete d;
}
@@ -111,9 +118,6 @@ void Viewer::InstallPipe() {
}
void Viewer::UninstallPipe() {
if (GetRenderer()) {
GetRenderer()->RemoveAllViewProps();
}
}
void Viewer::Render() {

View File

@@ -100,6 +100,7 @@ vtkHandlerWidget::vtkHandlerWidget() : d(new HandlerWidgetData()) {
}
vtkHandlerWidget::~vtkHandlerWidget() {
this->SetEnabled(0);
delete d;
}
@@ -194,9 +195,12 @@ void vtkHandlerWidget::SetEnabled(int enabling) {
this->Enabled = 0;
this->Highlight(nullptr);
this->Interactor->RemoveObserver(this->EventCallbackCommand);
if (this->Interactor->GetRenderWindow()) {
this->Interactor->GetRenderWindow()->RemoveRenderer(this->d->m_OverlayRenderer);
if (this->Interactor) {
this->Interactor->RemoveObserver(this->EventCallbackCommand);
if (this->Interactor->GetRenderWindow()) {
this->Interactor->GetRenderWindow()->MakeCurrent();
this->Interactor->GetRenderWindow()->RemoveRenderer(this->d->m_OverlayRenderer);
}
}
this->d->m_OverlayRenderer->RemoveAllViewProps();
this->InvokeEvent(::vtkCommand::DisableEvent, nullptr);
@@ -792,21 +796,23 @@ void vtkHandlerWidget::UpdateGizmoPosition() {
if (bboxSize < 1e-6) bboxSize = 1.0;
double screenLimit = bboxSize * 2.0; // Default if no renderer
if (this->CurrentRenderer) {
int *sz = this->CurrentRenderer->GetSize();
if (sz[1] > 0) {
double pixelSize = std::min(sz[0], sz[1]) / 5.0;
vtkCamera *cam = this->CurrentRenderer->GetActiveCamera();
if (cam->GetParallelProjection()) {
screenLimit = (pixelSize / (double)sz[1]) * 2.0 * cam->GetParallelScale();
} else {
double dist = cam->GetDistance();
double angleRad = vtkMath::Pi() * cam->GetViewAngle() / 180.0;
double viewHeightAtDist = 2.0 * dist * tan(angleRad / 2.0);
screenLimit = (pixelSize / (double)sz[1]) * viewHeightAtDist;
if (this->CurrentRenderer && this->CurrentRenderer->GetRenderWindow() && this->CurrentRenderer->GetRenderWindow()->GetInteractor()) {
int *sz = this->CurrentRenderer->GetSize();
if (sz[1] > 0) {
double pixelSize = std::min(sz[0], sz[1]) / 5.0;
vtkCamera *cam = this->CurrentRenderer->GetActiveCamera();
if (cam) {
if (cam->GetParallelProjection()) {
screenLimit = (pixelSize / (double)sz[1]) * 2.0 * cam->GetParallelScale();
} else {
double dist = cam->GetDistance();
double angleRad = vtkMath::Pi() * cam->GetViewAngle() / 180.0;
double viewHeightAtDist = 2.0 * dist * tan(angleRad / 2.0);
screenLimit = (pixelSize / (double)sz[1]) * viewHeightAtDist;
}
}
}
}
}
double scaleFactor = std::min(bboxSize, screenLimit);
vtkNew<vtkMatrix4x4> mat_gizmo;

View File

@@ -64,9 +64,23 @@ Viewport::Viewport()
{
}
void Viewport::DisableHandler() {
if (d->m_HandlerWidget) {
d->m_HandlerWidget->SetEnabled(0);
}
}
Viewport::~Viewport()
{
if (d->m_HandlerWidget) {
d->m_HandlerWidget->SetEnabled(0);
d->m_HandlerWidget = nullptr;
}
if (d->m_Renderer) {
if (d->m_Renderer->GetActiveCamera()) {
d->m_Renderer->GetActiveCamera()->RemoveAllObservers();
}
d->m_Renderer->RemoveAllObservers();
d->m_Renderer->RemoveAllViewProps();
}
delete d;

View File

@@ -58,6 +58,7 @@ public:
virtual vtkRenderWindowInteractor* GetInteractor() = 0;
vtkCornerAnnotation* GetAnnotation();
vtkCameraOrientationWidget* GetCameraWidget();
void DisableHandler();
const std::vector<Puppet*>& getPuppets() const { return m_Puppets; }
// Grid control