emitter representation

This commit is contained in:
AndreaRigoni
2026-03-19 13:57:10 +00:00
parent ca5f576b99
commit 1e6e3ae4f4
9 changed files with 261 additions and 9 deletions

View File

@@ -29,14 +29,14 @@ EmitterPrimary::EmitterPrimary()
// Configuriamo le proprietà iniziali della particella
fParticleGun->SetParticleDefinition(particle);
// Impostiamo la direzione della quantità di moto (es. lungo l'asse Z)
fParticleGun->SetParticleMomentumDirection(G4ThreeVector(0., 0., -1.));
// Impostiamo l'energia cinetica a 1 GeV
fParticleGun->SetParticleEnergy(1.0 * GeV);
// Impostiamo la posizione di partenza (origine)
fParticleGun->SetParticlePosition(G4ThreeVector(0., 0., 10. * m));
// Initial position and direction through AffineTransform
// 10m on Z axis, pointing towards origin
this->SetPosition(Vector3f(0, 0, 10000.0));
// Default orientation is identity (pointing along -Z if we rotate the puppet accordingly)
// But fParticleGun defaults are set here and overridden in GeneratePrimaries
}
EmitterPrimary::~EmitterPrimary() {
@@ -45,9 +45,14 @@ EmitterPrimary::~EmitterPrimary() {
}
void EmitterPrimary::GeneratePrimaries(G4Event *anEvent) {
// Questo metodo viene invocato all'inizio di ogni evento.
// Qui potresti anche aggiungere una randomizzazione della posizione o
// dell'energia.
// Use position and direction from AffineTransform
Vector3f pos = this->GetPosition();
// Assume default direction is along the -Z axis of the local frame
Vector4f dir4 = this->GetWorldMatrix() * Vector4f(0, 0, -1, 0);
Vector3f dir = dir4.head<3>().normalized();
fParticleGun->SetParticlePosition(G4ThreeVector(pos(0), pos(1), pos(2)));
fParticleGun->SetParticleMomentumDirection(G4ThreeVector(dir(0), dir(1), dir(2)));
fParticleGun->GeneratePrimaryVertex(anEvent);
}

View File

@@ -4,7 +4,13 @@
#include "G4VUserPrimaryGeneratorAction.hh"
#include "globals.hh"
namespace uLib {
class QuadMesh;
}
#include "Math/QuadMesh.h"
#include "Core/Object.h"
#include "Math/Transform.h"
#include <vector> // Added for std::vector
class G4ParticleGun;
@@ -13,7 +19,7 @@ class G4Event;
namespace uLib {
namespace Geant {
class EmitterPrimary : public G4VUserPrimaryGeneratorAction
class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public Object, public AffineTransform
{
public:
EmitterPrimary();
@@ -22,11 +28,14 @@ class EmitterPrimary : public G4VUserPrimaryGeneratorAction
// Metodo principale chiamato all'inizio di ogni evento
virtual void GeneratePrimaries(G4Event*);
virtual void Updated() override { ULIB_SIGNAL_EMIT(EmitterPrimary::Updated); }
protected:
G4ParticleGun* fParticleGun; // Puntatore al cannone di particelle
};
class QuadMeshEmitterPrimary : public EmitterPrimary
{
public:

View File

@@ -50,6 +50,7 @@
#define U_TRANSFORM_H
#include <Eigen/Geometry>
#include "Math/Dense.h"
namespace uLib {

View File

@@ -5,10 +5,12 @@
set(HEP_GEANT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.cpp
PARENT_SCOPE)
set(HEP_GEANT_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/vtkGeantEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/vtkEmitterPrimary.h
PARENT_SCOPE)
if(BUILD_TESTING)

View File

@@ -1,6 +1,7 @@
# TESTS
set(TESTS
vtkGeantEventTest
vtkEmitterPrimaryTest
)
set(LIBRARIES

View File

@@ -0,0 +1,124 @@
#include "Geant/Solid.h"
#include "HEP/Geant/GeantEvent.h"
#include "HEP/Geant/Scene.h"
#include "HEP/Geant/EmitterPrimary.hh"
#include "Math/ContainerBox.h"
#include "Math/Dense.h"
#include "Math/Units.h"
#include "Vtk/uLibVtkViewer.h"
#include "Vtk/HEP/Geant/vtkGeantEvent.h"
#include "Vtk/HEP/Geant/vtkEmitterPrimary.h"
#include "Vtk/vtkContainerBox.h"
#include <vtkSmartPointer.h>
#include <vtkCallbackCommand.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <Geant4/Randomize.hh>
#include <Geant4/G4ParticleGun.hh>
#include <Geant4/G4SystemOfUnits.hh>
#include <iostream>
using namespace uLib;
struct AppState {
Geant::Scene* scene;
Vtk::Viewer* viewer;
Vector<Geant::GeantEvent> results;
};
void KeyPressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) {
auto* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
auto* state = static_cast<AppState*>(clientData);
std::string key = interactor->GetKeySym();
if (key == "Return") {
std::cout << "--> Firing muon from current emitter position..." << std::endl;
// Run one event
state->scene->RunSimulation(1, state->results);
if (!state->results.empty()) {
// Get the last event
Geant::GeantEvent* lastEvent = &state->results.back();
std::cout << " Collected event " << lastEvent->GetEventID()
<< " with " << lastEvent->Path().size() << " steps." << std::endl;
// Wrap it for VTK
Vtk::vtkGeantEvent* vtkEvent = new Vtk::vtkGeantEvent(lastEvent);
state->viewer->AddPuppet(*vtkEvent);
// Re-render
state->viewer->GetRenderer()->Render();
state->viewer->GetRenderWindow()->Render();
}
else {
std::cout << " No event collected." << std::endl;
}
}
}
int main(int argc, char** argv) {
// 1. Setup Geant4 Scene
Geant::Scene scene;
scene.ConstructWorldBox(Vector3f(30_m, 30_m, 30_m), "G4_AIR");
ContainerBox iron_box;
iron_box.Scale(Vector3f(10_m, 10_m, 10_m));
iron_box.SetPosition(Vector3f(0, 0, 0));
Geant::BoxSolid* iron_cube = new Geant::BoxSolid("IronCube", &iron_box);
iron_cube->SetNistMaterial("G4_Fe");
iron_cube->Update();
scene.AddSolid(iron_cube);
Geant::EmitterPrimary* emitter = new Geant::EmitterPrimary();
emitter->SetPosition(Vector3f(0, 0, 14_m));
scene.SetEmitter(emitter);
scene.Initialize();
// 2. Setup VTK Viewer
Vtk::Viewer viewer;
viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1);
// Visualize world box
Vtk::vtkContainerBox* vtkWorld = new Vtk::vtkContainerBox(scene.GetWorldBox());
vtkWorld->ShowScaleMeasures(true);
vtkWorld->SetRepresentation(Vtk::Puppet::Wireframe);
vtkWorld->SetSelectable(false);
viewer.AddPuppet(*vtkWorld);
// Visualize iron cube
Vtk::vtkContainerBox* vtkIron = new Vtk::vtkContainerBox(&iron_box);
vtkIron->SetOpacity(0.2);
vtkIron->SetRepresentation(Vtk::Puppet::Surface);
viewer.AddPuppet(*vtkIron);
// Visualize Emitter
Vtk::vtkEmitterPrimary* vtkEmitter = new Vtk::vtkEmitterPrimary(*emitter);
viewer.AddPuppet(*vtkEmitter);
// 3. Event Handling
AppState state = { &scene, &viewer, {} };
vtkSmartPointer<vtkCallbackCommand> keyCallback = vtkSmartPointer<vtkCallbackCommand>::New();
keyCallback->SetCallback(KeyPressCallbackFunction);
keyCallback->SetClientData(&state);
viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback);
std::cout << "=================================================" << std::endl;
std::cout << " Geant Muon Interactive Emitter Test" << std::endl;
std::cout << " Use the Widget to move/rotate the Arrow (Emitter)" << std::endl;
std::cout << " Press [ENTER] to fire a muon" << std::endl;
std::cout << " Press [q] to exit" << std::endl;
std::cout << "=================================================" << std::endl;
viewer.ZoomAuto();
viewer.Start();
return 0;
}

View File

@@ -0,0 +1,72 @@
#include "vtkEmitterPrimary.h"
#include <vtkActor.h>
#include <vtkArrowSource.h>
#include <vtkMatrix4x4.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include "Math/vtkDense.h"
namespace uLib {
namespace Vtk {
vtkEmitterPrimary::vtkEmitterPrimary(Geant::EmitterPrimary &emitter)
: m_emitter(emitter), m_Poly(nullptr), m_Actor(vtkActor::New()) {
vtkNew<vtkArrowSource> arrow;
// Default arrow is along X+. Rotate to point towards Z- relative to the origin
vtkNew<vtkTransform> transform;
transform->RotateY(90.0);
vtkNew<vtkTransformPolyDataFilter> transformFilter;
transformFilter->SetTransform(transform);
transformFilter->SetInputConnection(arrow->GetOutputPort());
transformFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(transformFilter->GetOutput());
m_Actor->SetMapper(mapper);
m_Actor->SetScale(1000.0); // 1 meter long
vtkNew<vtkMatrix4x4> vmat;
Matrix4fToVtk(m_emitter.GetWorldMatrix(), vmat);
m_Actor->SetUserMatrix(vmat);
this->SetProp(m_Actor);
Object::connect(&m_emitter, &Object::Updated, this, &vtkEmitterPrimary::contentUpdate);
this->contentUpdate();
}
vtkEmitterPrimary::~vtkEmitterPrimary() {
Object::disconnect(&m_emitter, &Object::Updated, this, &vtkEmitterPrimary::contentUpdate);
m_Actor->Delete();
}
void vtkEmitterPrimary::contentUpdate() {
vtkMatrix4x4 *vmat = m_Actor->GetUserMatrix();
if (!vmat) {
vtkNew<vtkMatrix4x4> mat;
m_Actor->SetUserMatrix(mat);
vmat = mat;
}
Matrix4f transform = m_emitter.GetWorldMatrix();
Matrix4fToVtk(transform, vmat);
Puppet::Update();
}
void vtkEmitterPrimary::Update() {
vtkMatrix4x4 *vmat = m_Actor->GetUserMatrix();
if (!vmat) return;
Matrix4f transform = VtkToMatrix4f(vmat);
m_emitter.SetMatrix(transform);
m_emitter.Updated();
}
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,32 @@
#ifndef VTK_GEANT_EMITTERPRIMARY_H
#define VTK_GEANT_EMITTERPRIMARY_H
#include "Vtk/uLibVtkInterface.h"
#include "HEP/Geant/EmitterPrimary.hh"
class vtkConeSource;
class vtkLineSource;
class vtkPolyData;
class vtkActor;
namespace uLib {
namespace Vtk {
class vtkEmitterPrimary : public Puppet {
public:
vtkEmitterPrimary(Geant::EmitterPrimary &emitter);
virtual ~vtkEmitterPrimary();
virtual void contentUpdate();
virtual void Update();
private:
Geant::EmitterPrimary &m_emitter;
vtkPolyData *m_Poly;
vtkActor *m_Actor;
};
} // namespace Vtk
} // namespace uLib
#endif // VTK_GEANT_EMITTERPRIMARY_H

View File

@@ -215,6 +215,7 @@ vtkProp *Puppet::GetProp()
void Puppet::SetProp(vtkProp *prop)
{
if(prop) {
prop->SetPickable(d->m_Selectable);
if (auto* p3d = vtkProp3D::SafeDownCast(prop)) {
d->m_Assembly->AddPart(p3d);
}
@@ -414,6 +415,11 @@ void Puppet::SetOpacity(double alpha)
void Puppet::SetSelectable(bool selectable)
{
d->m_Selectable = selectable;
vtkProp3DCollection *props = d->m_Assembly->GetParts();
props->InitTraversal();
for (int i = 0; i < props->GetNumberOfItems(); ++i) {
props->GetNextProp3D()->SetPickable(selectable);
}
}
bool Puppet::IsSelectable() const