diff --git a/app/gcompose/src/PropertyWidgets.cpp b/app/gcompose/src/PropertyWidgets.cpp index 1c586c5..3c87bf9 100644 --- a/app/gcompose/src/PropertyWidgets.cpp +++ b/app/gcompose/src/PropertyWidgets.cpp @@ -36,6 +36,8 @@ PropertyWidgetBase::PropertyWidgetBase(PropertyBase* prop, QWidget* parent) m_Label = new QLabel(labelText, this); m_Label->setMinimumWidth(120); m_Layout->addWidget(m_Label); + + this->setEnabled(!prop->IsReadOnly()); } PropertyWidgetBase::~PropertyWidgetBase() { m_Connection.disconnect(); @@ -150,7 +152,7 @@ DoublePropertyWidget::DoublePropertyWidget(Property* prop, QWidget* pare m_Edit->setValue(prop->Get()); m_Layout->addWidget(m_Edit, 1); connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set(val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ m_Edit->setValue(m_Prop->Get()); }); } @@ -168,7 +170,7 @@ FloatPropertyWidget::FloatPropertyWidget(Property* prop, QWidget* parent) m_Edit->setValue(prop->Get()); m_Layout->addWidget(m_Edit, 1); connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((float)val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ m_Edit->setValue((double)m_Prop->Get()); }); } @@ -187,7 +189,7 @@ IntPropertyWidget::IntPropertyWidget(Property* prop, QWidget* parent) m_Edit->setValue(prop->Get()); m_Layout->addWidget(m_Edit, 1); connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((int)val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ m_Edit->setValue((double)m_Prop->Get()); }); } @@ -198,7 +200,7 @@ BoolPropertyWidget::BoolPropertyWidget(Property* prop, QWidget* parent) m_CheckBox->setChecked(prop->Get()); m_Layout->addWidget(m_CheckBox, 1); connect(m_CheckBox, &QCheckBox::toggled, [this](bool val){ if (m_Prop->Get() != val) m_Prop->Set(val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ if (m_CheckBox->isChecked() != m_Prop->Get()) { QSignalBlocker blocker(m_CheckBox); m_CheckBox->setChecked(m_Prop->Get()); @@ -222,7 +224,7 @@ RangePropertyWidget::RangePropertyWidget(Property* prop, QWidget* parent connect(m_Slider, &QSlider::valueChanged, this, &RangePropertyWidget::onSliderChanged); connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set(val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ this->updateUi(); }); updateUi(); @@ -252,7 +254,7 @@ ColorPropertyWidget::ColorPropertyWidget(Property* prop, QWidget* pare m_Layout->addWidget(m_Button, 0, ::Qt::AlignRight); connect(m_Button, &QPushButton::clicked, this, &ColorPropertyWidget::onClicked); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ this->updateButtonColor(); }); } @@ -286,7 +288,7 @@ StringPropertyWidget::StringPropertyWidget(Property* prop, QWidget* std::string val = m_LineEdit->text().toStdString(); if (m_Prop->Get() != val) m_Prop->Set(val); }); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ if (m_LineEdit->text().toStdString() != m_Prop->Get()) { QSignalBlocker blocker(m_LineEdit); m_LineEdit->setText(QString::fromStdString(m_Prop->Get())); @@ -334,7 +336,7 @@ public: p->Set(index); }); // Store connection in base m_Connection so it's auto-disconnected on destruction. - m_Connection = uLib::Object::connect(p, &Property::PropertyChanged, [this, p](){ + m_Connection = uLib::Object::connect(p, &Property::Updated, [this, p](){ if (m_Combo->currentIndex() != p->Get()) { QSignalBlocker blocker(m_Combo); m_Combo->setCurrentIndex(p->Get()); diff --git a/app/gcompose/src/PropertyWidgets.h b/app/gcompose/src/PropertyWidgets.h index 7374389..3eca02f 100644 --- a/app/gcompose/src/PropertyWidgets.h +++ b/app/gcompose/src/PropertyWidgets.h @@ -115,6 +115,7 @@ public: if (!prefSuffix.isEmpty()) { m_Edits[i]->setUnits(prefSuffix, factor); } + m_Edits[i]->setEnabled(!prop->IsReadOnly()); m_Layout->addWidget(m_Edits[i], 1); connect(m_Edits[i], &UnitLineEdit::valueManualChanged, [this, i](double val){ @@ -124,7 +125,7 @@ public: }); } updateEdits(); - m_Connection = uLib::Object::connect(m_Prop, &Property::PropertyChanged, [this](){ + m_Connection = uLib::Object::connect(m_Prop, &Property::Updated, [this](){ updateEdits(); }); } diff --git a/docs/geant_integration.md b/docs/geant_integration.md new file mode 100644 index 0000000..d51b002 --- /dev/null +++ b/docs/geant_integration.md @@ -0,0 +1,11 @@ +# Geant integration + +Geant4 integration in uLib is done through the `HEP/Geant` module. +The module represets a set of wrapper for geant objects that are also deriving from uLib::Object so they can be used in the uLib::Object tree and visualized with the uLib::Vtk module and driven py properties. + +# Geant Solid integration + +Geant solid in uLib is represented by the `uLib::Geant::Solid` class and mainly BoxSolid and TessellatedSolid. The solids in Geant does not have the possibility to set properties on the fly so we need to create a new solid every time we want to change the properties of a solid. This is done by creating a new `uLib::Geant::Solid` object and setting the properties of the new solid. The new solid is then added to the `uLib::Geant::Solid` object as a child. The old solid is then removed from the `uLib::Geant::Solid` object as a child. The old solid is then deleted. However id some of the properties can be set then the library will drive the change in the solid update. + +The idea is to have a mapping of solid properties that can be used in uLib for Qt representation or vtk representation. then when the property is changed the signaling will update the property in uLib and then the solid will be updated. If the Geant property can be applied to the G4 object underneath then the update will apply the change, in case it is not possible to apply the change to the G4 object underneath then the G4 element will be recreated. +In any case a updated singal is emitted and the related element that use that solid is updated ( for instance the scene ). \ No newline at end of file diff --git a/src/HEP/Geant/CMakeLists.txt b/src/HEP/Geant/CMakeLists.txt index 7ad33ec..874483b 100644 --- a/src/HEP/Geant/CMakeLists.txt +++ b/src/HEP/Geant/CMakeLists.txt @@ -27,6 +27,8 @@ set(SOURCES Scene.cpp Solid.cpp EmitterPrimary.cpp + Matter.cpp + GeantRegistration.cpp DetectorConstruction.cpp PhysicsList.cpp ActionInitialization.cpp diff --git a/src/HEP/Geant/GeantRegistration.cpp b/src/HEP/Geant/GeantRegistration.cpp new file mode 100644 index 0000000..b148d3d --- /dev/null +++ b/src/HEP/Geant/GeantRegistration.cpp @@ -0,0 +1,22 @@ +#include "Core/ObjectFactory.h" +#include "HEP/Geant/Matter.h" +#include "HEP/Geant/Solid.h" +#include "HEP/Geant/Scene.h" +#include "HEP/Geant/EmitterPrimary.hh" +#include "HEP/Geant/GeantEvent.h" + +namespace uLib { +namespace Geant { + +ULIB_REGISTER_OBJECT(Material) +ULIB_REGISTER_OBJECT(Solid) +ULIB_REGISTER_OBJECT(TessellatedSolid) +ULIB_REGISTER_OBJECT(BoxSolid) +ULIB_REGISTER_OBJECT(Scene) +ULIB_REGISTER_OBJECT(SkyPlaneEmitterPrimary) +ULIB_REGISTER_OBJECT(CylinderEmitterPrimary) +ULIB_REGISTER_OBJECT(QuadMeshEmitterPrimary) +ULIB_REGISTER_OBJECT(GeantEvent) + +} // namespace Geant +} // namespace uLib diff --git a/src/HEP/Geant/Matter.cpp b/src/HEP/Geant/Matter.cpp new file mode 100644 index 0000000..f40345b --- /dev/null +++ b/src/HEP/Geant/Matter.cpp @@ -0,0 +1,21 @@ + +#include "HEP/Geant/Matter.h" +#include +#include + +using namespace uLib::Geant; + +Material::Material() : m_G4Data(nullptr) {} + +Material::Material(const char *name) : m_G4Data(nullptr) { + this->SetFromNist(name); +} + +Material::~Material() { + if(m_G4Data) delete m_G4Data; +} + +void Material::SetFromNist(const char *name) { + G4NistManager* man = G4NistManager::Instance(); + m_G4Data = man->FindOrBuildMaterial(name); +} \ No newline at end of file diff --git a/src/HEP/Geant/Matter.h b/src/HEP/Geant/Matter.h index 64e35d0..1df6573 100644 --- a/src/HEP/Geant/Matter.h +++ b/src/HEP/Geant/Matter.h @@ -29,9 +29,10 @@ #define MATTER_H #include "Core/Object.h" +#include +#include class G4Element; -class G4Material; namespace uLib { namespace Geant { @@ -55,19 +56,55 @@ private: //// MATERIAL ////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// +// TODO: finish from G4NistMaterialBuilder class Material : public Object { public: + enum State { + Undefined = 0, + Solid, + Liquid, + Gas + }; + virtual const char* GetClassName() const override { return "Geant.Material"; } - uLibRefMacro(G4Data,G4Material *) + Material(); + Material(const char *name); + ~Material(); + + void SetFromNist(const char *name); + + template + void serialize(Ar &ar) { + ar & HRP("name", m_G4Data->GetName()); + ar & HRP("density", m_G4Data->GetDensity()); + ar & serialization::make_hrp_enum("state", m_G4Data->GetState(), {"Undefined", "Solid", "Liquid", "Gas"}); + } + + G4Material *GetG4Material() { return m_G4Data; } + private: G4Material *m_G4Data; + }; +// class MaterialCompound : public Material { +// public: - +// MaterialCompound(const char *name) {} + +// void AddMaterial(Material *m, double fractionmass) { m_Materials.push_back(std::make_pair(m, fractionmass)); } +// void AddElement(Element *e, double fractionmass) { m_Elements.push_back(std::make_pair(e, fractionmass)); } +// void SetDensity(double density) { m_Density = density; } + +// private: +// std::vector> m_Materials; +// std::vector> m_Elements; +// double m_Density; +// }; + } } diff --git a/src/HEP/Geant/Solid.cpp b/src/HEP/Geant/Solid.cpp index 54456a3..16a99ee 100644 --- a/src/HEP/Geant/Solid.cpp +++ b/src/HEP/Geant/Solid.cpp @@ -146,6 +146,9 @@ void Solid::SetParent(Solid *parent) { +TessellatedSolid::TessellatedSolid() + : BaseClass("unnamed_tessellated"), m_Solid(new G4TessellatedSolid("unnamed_tessellated")) {} + TessellatedSolid::TessellatedSolid(const char *name) : BaseClass(name), m_Solid(new G4TessellatedSolid(name)) { } @@ -173,9 +176,15 @@ void TessellatedSolid::Update() { +BoxSolid::BoxSolid(const char *name) : + BaseClass(name), + m_ContainerBox(new ContainerBox()), + m_Solid(new G4Box(name, 1, 1, 1)) + {} + BoxSolid::BoxSolid(const char *name, ContainerBox *box) : BaseClass(name) { - m_Solid = new G4Box(name, 1,1,1); - m_Object = box; + m_Solid = new G4Box(name, 1, 1, 1); + m_ContainerBox = box; Object::connect(box, &ContainerBox::Updated, this, &BoxSolid::Update); if (m_Logical) { m_Logical->SetSolid(m_Solid); @@ -184,27 +193,30 @@ BoxSolid::BoxSolid(const char *name, ContainerBox *box) : BaseClass(name) { } void BoxSolid::Update() { - if (m_Object) { - Vector3f size = m_Object->GetSize(); + if (m_ContainerBox) { + Vector3f size = m_ContainerBox->GetSize(); m_Solid->SetXHalfLength(size(0) * 0.5); m_Solid->SetYHalfLength(size(1) * 0.5); m_Solid->SetZHalfLength(size(2) * 0.5); // Geant4 placement is relative to center. uLib Box is anchored at corner. // 1. Get position and rotation (clean, without scale) - Vector3f pos = m_Object->GetPosition(); - Matrix3f rot = m_Object->GetRotation(); + Vector3f pos = m_ContainerBox->GetPosition(); + Matrix3f rot = m_ContainerBox->GetRotation(); // 2. Center = Corner + Rotation * (Half-Size) // We must rotate the offset vector because uLib box can be rotated. Vector3f center = pos + rot * (size * 0.5); - uLib::AffineTransform t; + uLib::AffineTransform t; t.SetPosition(center); t.SetRotation(rot); this->SetTransform(t.GetMatrix()); } + + + } diff --git a/src/HEP/Geant/Solid.h b/src/HEP/Geant/Solid.h index d05459b..82fac46 100644 --- a/src/HEP/Geant/Solid.h +++ b/src/HEP/Geant/Solid.h @@ -52,6 +52,7 @@ public: void SetNistMaterial(const char *name); void SetMaterial(G4Material *material); + void SetSizeUnit(const char *unit); // Implementiamo SetParent qui, per tutti. virtual void SetParent(Solid *parent); @@ -69,6 +70,14 @@ public: return m_Logical ? m_Logical->GetName().c_str() : m_Name.c_str(); } + template < typename Ar > + void serialize(Ar &ar, const unsigned int version) { + ar & m_Name; + } + + + + protected: std::string m_Name; @@ -89,6 +98,7 @@ public: virtual const char* GetClassName() const override { return "Geant.TessellatedSolid"; } + TessellatedSolid(); TessellatedSolid(const char *name); void SetMesh(TriangleMesh &mesh); uLibGetMacro(Solid, G4TessellatedSolid *) @@ -116,16 +126,23 @@ public: virtual const char* GetClassName() const override { return "Geant.BoxSolid"; } + BoxSolid(const char *name = ""); BoxSolid(const char *name, ContainerBox *box); virtual G4VSolid* GetG4Solid() const override { return (G4VSolid*)m_Solid; } - ContainerBox* GetObject() const { return m_Object; } + ContainerBox* GetObject() const { return m_ContainerBox; } + + template < typename Ar > + void serialize(Ar &ar, const unsigned int version) { + ar & boost::serialization::base_object(*this); + ar & m_ContainerBox; + } public slots: void Update(); private: - ContainerBox *m_Object; + ContainerBox *m_ContainerBox; G4Box *m_Solid; }; diff --git a/src/Vtk/uLibVtkInterface.cxx b/src/Vtk/uLibVtkInterface.cxx index 106e054..1dcbef0 100644 --- a/src/Vtk/uLibVtkInterface.cxx +++ b/src/Vtk/uLibVtkInterface.cxx @@ -603,6 +603,8 @@ void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor) } + + // ------------------------------------------------------ // // SERIALIZE DISPLAY PROPERTIES