attach vtk context to gcompose

This commit is contained in:
AndreaRigoni
2026-03-22 12:18:33 +00:00
parent a8f786d8d1
commit 324aaa91b7
36 changed files with 674 additions and 19 deletions

View File

@@ -3,6 +3,7 @@
#include <typeinfo>
#include <cxxabi.h>
#include <functional>
#include "Core/Object.h"
ContextModel::ContextModel(QObject* parent)
: QAbstractItemModel(parent), m_rootContext(nullptr) {}
@@ -12,6 +13,12 @@ ContextModel::~ContextModel() {}
void ContextModel::setContext(uLib::ObjectsContext* context) {
beginResetModel();
m_rootContext = context;
if (m_rootContext) {
uLib::Object::connect(m_rootContext, &uLib::Object::Updated, [this]() {
this->beginResetModel();
this->endResetModel();
});
}
endResetModel();
}
@@ -118,7 +125,14 @@ QVariant ContextModel::data(const QModelIndex& index, int role) const {
uLib::Object* obj = static_cast<uLib::Object*>(index.internalPointer());
if (role == Qt::DisplayRole) {
return getDemangledName(typeid(*obj));
QString typeName = getDemangledName(typeid(*obj));
std::string instName = obj->GetInstanceName();
if (instName.empty()) return typeName;
return QString("%1 (%2)").arg(QString::fromStdString(instName)).arg(typeName);
}
if (role == Qt::EditRole) {
return QString::fromStdString(obj->GetInstanceName());
}
return QVariant();
@@ -130,3 +144,18 @@ QVariant ContextModel::headerData(int section, Qt::Orientation orientation, int
}
return QVariant();
}
Qt::ItemFlags ContextModel::flags(const QModelIndex& index) const {
if (!index.isValid()) return Qt::NoItemFlags;
return Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
bool ContextModel::setData(const QModelIndex& index, const QVariant& value, int role) {
if (index.isValid() && role == Qt::EditRole) {
uLib::Object* obj = static_cast<uLib::Object*>(index.internalPointer());
obj->SetInstanceName(value.toString().toStdString());
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
return true;
}
return false;
}

View File

@@ -18,6 +18,8 @@ public:
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
private:
uLib::ObjectsContext* m_rootContext;

View File

@@ -4,8 +4,16 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QTreeView>
#include <QSplitter>
#include <QList>
#include <QShortcut>
#include <QItemSelectionModel>
#include <Vtk/vtkQViewport.h>
#include <Vtk/vtkObjectsContext.h>
ContextPanel::ContextPanel(QWidget* parent) : QWidget(parent) {
ContextPanel::ContextPanel(QWidget* parent)
: QWidget(parent)
, m_vtkContext(nullptr) {
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setSpacing(0);
@@ -32,12 +40,92 @@ ContextPanel::ContextPanel(QWidget* parent) : QWidget(parent) {
m_model = new ContextModel(this);
m_treeView->setModel(m_model);
m_layout->addWidget(m_treeView);
m_splitter = new QSplitter(Qt::Vertical, this);
m_splitter->addWidget(m_treeView);
m_vtkView = new uLib::Vtk::QViewport(m_splitter);
m_splitter->addWidget(m_vtkView);
QList<int> sizes;
sizes << 400 << 200;
m_splitter->setSizes(sizes);
m_layout->addWidget(m_splitter);
connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &ContextPanel::onSelectionChanged);
auto* deleteShortcut = new QShortcut(QKeySequence::Delete, this);
connect(deleteShortcut, &QShortcut::activated, [this]() {
auto selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
if (selectedIndexes.isEmpty() || !m_context) return;
// Collect objects to remove to avoid iterator invalidation issues if context signal emits during removal
std::vector<uLib::Object*> toRemove;
for (const auto& idx : selectedIndexes) {
if (idx.column() == 0) {
toRemove.push_back(static_cast<uLib::Object*>(idx.internalPointer()));
}
}
for (auto* obj : toRemove) {
m_context->RemoveObject(obj);
}
});
}
ContextPanel::~ContextPanel() {}
void ContextPanel::setContext(uLib::ObjectsContext* context) {
m_context = context;
m_model->setContext(context);
m_treeView->expandAll();
if (m_vtkContext) {
m_vtkView->RemovePuppet(*m_vtkContext);
delete m_vtkContext;
}
m_vtkContext = new uLib::Vtk::vtkObjectsContext(context);
m_vtkView->AddPuppet(*m_vtkContext);
// Render viewport and add child puppets when context is updated
if (context) {
uLib::Object::connect(m_vtkContext, &uLib::Vtk::vtkObjectsContext::PuppetAdded, [this](uLib::Vtk::Puppet* p) {
if (this->m_vtkView && p) {
this->m_vtkView->AddPuppet(*p);
this->m_vtkView->ZoomAuto();
this->m_vtkView->Render();
}
});
// Add any puppets that were created during m_vtkContext's construction
for (auto* obj : context->GetObjects()) {
if (auto* p = m_vtkContext->GetPuppet(obj)) {
this->m_vtkView->AddPuppet(*p);
}
}
uLib::Object::connect(context, &uLib::Object::Updated, [this]() {
if (this->m_vtkView) {
this->m_vtkView->ZoomAuto();
this->m_vtkView->Render();
}
});
}
m_vtkView->Render();
}
void ContextPanel::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
uLib::Object* target = nullptr;
if (!selected.indexes().isEmpty()) {
target = static_cast<uLib::Object*>(selected.indexes().first().internalPointer());
}
emit objectSelected(target);
if (m_vtkContext) {
auto* puppet = m_vtkContext->GetPuppet(target);
m_vtkView->SelectPuppet(puppet);
}
}

View File

@@ -2,6 +2,7 @@
#define CONTEXT_PANEL_H
#include <QWidget>
#include <QItemSelection>
class QTreeView;
class QVBoxLayout;
@@ -9,9 +10,16 @@ class QLabel;
class ContextModel;
namespace uLib {
class Object;
class ObjectsContext;
namespace Vtk {
class QViewport;
class vtkObjectsContext;
}
}
class QSplitter;
class ContextPanel : public QWidget {
Q_OBJECT
public:
@@ -20,12 +28,22 @@ public:
void setContext(uLib::ObjectsContext* context);
Q_SIGNALS:
void objectSelected(uLib::Object* obj);
private Q_SLOTS:
void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
private:
QVBoxLayout* m_layout;
QWidget* m_titleBar;
QLabel* m_titleLabel;
QTreeView* m_treeView;
ContextModel* m_model;
QSplitter* m_splitter;
uLib::Vtk::QViewport* m_vtkView;
uLib::Vtk::vtkObjectsContext* m_vtkContext;
uLib::ObjectsContext* m_context;
};
#endif // CONTEXT_PANEL_H

View File

@@ -1,6 +1,10 @@
#include "MainPanel.h"
#include "ViewportPane.h"
#include "ContextPanel.h"
#include "Core/ObjectFactory.h"
#include "Core/ObjectsContext.h"
#include "Vtk/vtkObjectsContext.h"
#include "Vtk/vtkQViewport.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
@@ -11,7 +15,7 @@
#include <QApplication>
#include "StyleManager.h"
MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
MainPanel::MainPanel(QWidget* parent) : QWidget(parent), m_context(nullptr), m_mainVtkContext(nullptr) {
auto* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
@@ -44,8 +48,23 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
themeMenu->addAction("Bright", this, &MainPanel::onBrightTheme);
btnTheme->setMenu(themeMenu);
// New Menu Button
auto* btnNew = new QPushButton("New", menuPanel);
btnNew->setObjectName("MenuButton");
auto* newMenu = new QMenu(btnNew);
auto classes = uLib::ObjectFactory::Instance().GetRegisteredClasses();
for (const auto& className : classes) {
auto* action = newMenu->addAction(QString::fromStdString(className));
connect(action, &QAction::triggered, [this, className]() {
this->onCreateObject(className);
});
}
btnNew->setMenu(newMenu);
menuLayout->addWidget(logo);
menuLayout->addWidget(btnFile);
menuLayout->addWidget(btnNew);
menuLayout->addWidget(btnTheme);
menuLayout->addStretch();
@@ -58,6 +77,16 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
m_firstPane = new ViewportPane(m_rootSplitter);
m_rootSplitter->addWidget(m_firstPane);
connect(m_contextPanel, &ContextPanel::objectSelected, [this](uLib::Object* obj) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
uLib::Vtk::Puppet* puppet = nullptr;
if (m_mainVtkContext) {
puppet = m_mainVtkContext->GetPuppet(obj);
}
viewport->SelectPuppet(puppet);
}
});
// Set initial sizes
QList<int> sizes;
sizes << 200 << 1000;
@@ -67,7 +96,52 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
}
void MainPanel::setContext(uLib::ObjectsContext* context) {
m_context = context;
m_contextPanel->setContext(context);
if (m_mainVtkContext) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
viewport->RemovePuppet(*m_mainVtkContext);
}
delete m_mainVtkContext;
m_mainVtkContext = nullptr;
}
if (context) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
m_mainVtkContext = new uLib::Vtk::vtkObjectsContext(context);
viewport->AddPuppet(*m_mainVtkContext);
uLib::Object::connect(m_mainVtkContext, &uLib::Vtk::vtkObjectsContext::PuppetAdded, [viewport](uLib::Vtk::Puppet* p) {
if (viewport && p) {
viewport->AddPuppet(*p);
viewport->ZoomAuto();
viewport->Render();
}
});
// Add any puppets that were created during m_mainVtkContext's construction
for (auto* obj : context->GetObjects()) {
if (auto* p = m_mainVtkContext->GetPuppet(obj)) {
viewport->AddPuppet(*p);
}
}
uLib::Object::connect(context, &uLib::Object::Updated, [viewport]() {
viewport->ZoomAuto();
viewport->Render();
});
viewport->ZoomAuto();
viewport->Render();
}
}
}
void MainPanel::onCreateObject(const std::string& className) {
if (!m_context) return;
auto* obj = uLib::ObjectFactory::Instance().Create(className);
if (obj) {
m_context->AddObject(obj);
}
}
void MainPanel::onOpen() {

View File

@@ -9,6 +9,9 @@ class ContextPanel;
namespace uLib {
class ObjectsContext;
namespace Vtk {
class vtkObjectsContext;
}
}
class MainPanel : public QWidget {
@@ -25,11 +28,15 @@ private slots:
void onSave();
void onDarkTheme();
void onBrightTheme();
void onCreateObject(const std::string& className);
private:
QSplitter* m_rootSplitter;
ViewportPane* m_firstPane;
ContextPanel* m_contextPanel;
uLib::ObjectsContext* m_context;
uLib::Vtk::vtkObjectsContext* m_mainVtkContext;
};
#endif // MAINPANEL_H

View File

@@ -33,7 +33,8 @@ int main(int argc, char** argv) {
std::cout << "Starting gcompose Qt application..." << std::endl;
ContainerBox world_box(Vector3f(1, 1, 1));
world_box.Scale(Vector3f(20_mm, 20_mm, 20_mm));
world_box.Scale(Vector3f(2_mm, 2_mm, 2_mm));
world_box.SetPosition(Vector3f(-1_mm, -1_mm, -1_mm));
Geant::Scene scene;
scene.ConstructWorldBox(world_box.GetSize(), "G4_AIR");
@@ -46,14 +47,7 @@ int main(int argc, char** argv) {
// 2. Initialize MainWindow (contains embedded VTK QViewport)
MainWindow window;
window.setContext(&globalContext);
MainPanel* panel = window.getPanel();
ViewportPane* pane = panel->getFirstPane();
Vtk::QViewport* viewport = qobject_cast<Vtk::QViewport*>(pane->currentViewport());
Vtk::vtkContainerBox vtk_box(&world_box);
viewport->AddPuppet(vtk_box);
viewport->ZoomAuto();
std::cout << "Geant4 and VTK scenes are ready." << std::endl;
window.show();

View File

@@ -10,6 +10,7 @@ set(HEADERS
Macros.h
Mpl.h
Object.h
ObjectFactory.h
ObjectsContext.h
Options.h
Serializable.h
@@ -27,6 +28,7 @@ set(SOURCES
Archives.cpp
Debug.cpp
Object.cpp
ObjectFactory.cpp
ObjectsContext.cpp
Options.cpp
Serializable.cpp

View File

@@ -56,7 +56,8 @@ public:
GenericMFPtr sloptr;
std::string slostr;
};
std::string m_InstanceName;
Vector<Signal> sigv;
Vector<Slot> slov;
};
@@ -147,6 +148,15 @@ GenericMFPtr *Object::findSlotImpl(const char *name) const {
void Object::Updated() { ULIB_SIGNAL_EMIT(Object::Updated); }
const std::string& Object::GetInstanceName() const {
return d->m_InstanceName;
}
void Object::SetInstanceName(const std::string& name) {
d->m_InstanceName = name;
this->Updated();
}
// std::ostream &
// operator << (std::ostream &os, uLib::Object &ob)
// {

View File

@@ -27,6 +27,7 @@
#define U_CORE_OBJECT_H
#include <iostream>
#include <string>
// WARNING: COPILE ERROR if this goes after mpl/vector //
// #include "Core/Vector.h"
@@ -74,6 +75,10 @@ public:
Object(const Object &copy);
~Object();
virtual const char * GetClassName() const { return "Object"; }
const std::string& GetInstanceName() const;
void SetInstanceName(const std::string& name);
////////////////////////////////////////////////////////////////////////////
// PARAMETERS //

View File

@@ -0,0 +1,32 @@
#include "ObjectFactory.h"
namespace uLib {
ObjectFactory& ObjectFactory::Instance() {
static ObjectFactory instance;
return instance;
}
void ObjectFactory::Register(const std::string& className, FactoryFunction func) {
if (m_factoryMap.find(className) == m_factoryMap.end()) {
m_factoryMap[className] = func;
}
}
Object* ObjectFactory::Create(const std::string& className) {
auto it = m_factoryMap.find(className);
if (it != m_factoryMap.end()) {
return (it->second)();
}
return nullptr;
}
std::vector<std::string> ObjectFactory::GetRegisteredClasses() const {
std::vector<std::string> classes;
for (auto const& [name, func] : m_factoryMap) {
classes.push_back(name);
}
return classes;
}
} // namespace uLib

68
src/Core/ObjectFactory.h Normal file
View File

@@ -0,0 +1,68 @@
#ifndef U_CORE_OBJECTFACTORY_H
#define U_CORE_OBJECTFACTORY_H
#include <string>
#include <map>
#include <vector>
#include <functional>
#include "Core/Object.h"
namespace uLib {
/**
* @brief Singleton factory for dynamic Object instantiation based on class name.
*/
class ObjectFactory {
public:
typedef std::function<Object*()> FactoryFunction;
/** @brief Get the singleton instance. */
static ObjectFactory& Instance();
/** @brief Register a factory function for a given class name. */
void Register(const std::string& className, FactoryFunction func);
/** @brief Create a new instance of the specified class. */
Object* Create(const std::string& className);
/** @brief Get the names of all registered classes. */
std::vector<std::string> GetRegisteredClasses() const;
private:
ObjectFactory() = default;
~ObjectFactory() = default;
// Prevent copy and assignment
ObjectFactory(const ObjectFactory&) = delete;
ObjectFactory& operator=(const ObjectFactory&) = delete;
std::map<std::string, FactoryFunction> m_factoryMap;
};
/**
* @brief Helper class to statically register a factory function.
*/
template <typename T>
class ObjectRegistrar {
public:
ObjectRegistrar(const std::string& className) {
ObjectFactory::Instance().Register(className, []() -> Object* { return new T(); });
}
};
#define ULIB_REG_CONCAT_IMPL(a, b) a##b
#define ULIB_REG_CONCAT(a, b) ULIB_REG_CONCAT_IMPL(a, b)
/**
* @brief Macro to register a class to the factory.
* Put this in the .cpp file of the class.
*/
#define ULIB_REGISTER_OBJECT(className) \
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(#className);
#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(registeredName);
} // namespace uLib
#endif // U_CORE_OBJECTFACTORY_H

View File

@@ -10,6 +10,7 @@ ObjectsContext::~ObjectsContext() {}
void ObjectsContext::AddObject(Object* obj) {
if (obj && std::find(m_objects.begin(), m_objects.end(), obj) == m_objects.end()) {
m_objects.push_back(obj);
ULIB_SIGNAL_EMIT(ObjectsContext::ObjectAdded, obj);
this->Updated(); // Signal that the context has been updated
}
}
@@ -17,13 +18,18 @@ void ObjectsContext::AddObject(Object* obj) {
void ObjectsContext::RemoveObject(Object* obj) {
auto it = std::find(m_objects.begin(), m_objects.end(), obj);
if (it != m_objects.end()) {
Object* removedObj = *it;
m_objects.erase(it);
ULIB_SIGNAL_EMIT(ObjectsContext::ObjectRemoved, removedObj);
this->Updated(); // Signal that the context has been updated
}
}
void ObjectsContext::Clear() {
if (!m_objects.empty()) {
for (auto obj : m_objects) {
ULIB_SIGNAL_EMIT(ObjectsContext::ObjectRemoved, obj);
}
m_objects.clear();
this->Updated();
}
@@ -44,4 +50,12 @@ Object* ObjectsContext::GetObject(size_t index) const {
return nullptr;
}
void ObjectsContext::ObjectAdded(Object* obj) {
ULIB_SIGNAL_EMIT(ObjectsContext::ObjectAdded, obj);
}
void ObjectsContext::ObjectRemoved(Object* obj) {
ULIB_SIGNAL_EMIT(ObjectsContext::ObjectRemoved, obj);
}
} // namespace uLib

View File

@@ -14,6 +14,8 @@ public:
ObjectsContext();
virtual ~ObjectsContext();
virtual const char * GetClassName() const { return "ObjectsContext"; }
/**
* @brief Adds an object to the context.
* @param obj Pointer to the object to add.
@@ -36,6 +38,12 @@ public:
* @return Const reference to the vector of object pointers.
*/
const std::vector<Object*>& GetObjects() const;
signals:
/** @brief Signal emitted when an object is added. */
virtual void ObjectAdded(Object* obj);
/** @brief Signal emitted when an object is removed. */
virtual void ObjectRemoved(Object* obj);
/**
* @brief Returns the number of objects in the context.

View File

@@ -43,11 +43,23 @@ using namespace boost::placeholders;
// Signals macro //
#define default(vlaue)
#define slots
#ifndef Q_MOC_RUN
#ifndef signals
#define signals /*virtual void init_signals();*/ public
#endif
#ifndef slots
#define slots
#endif
#ifndef emit
#define emit
#endif
#endif
#ifndef SLOT
#define SLOT(a) BOOST_STRINGIZE(a)
#endif
#ifndef SIGNAL
#define SIGNAL(a) BOOST_STRINGIZE(a)
#endif
#define _ULIB_DETAIL_SIGNAL_EMIT(_name, ...) \
do { \

View File

@@ -1,4 +1,5 @@
#include "HEP/Detectors/DetectorChamber.h"
#include "Core/ObjectFactory.h"
#include <cmath>
namespace uLib {
@@ -43,4 +44,6 @@ MuonEvent DetectorChamber::ProjectMuonEvent(const MuonEvent &muon) const {
return projectedMuon;
}
ULIB_REGISTER_OBJECT(DetectorChamber)
} // namespace uLib

View File

@@ -45,6 +45,8 @@ class DetectorChamber : public ContainerBox {
public:
virtual const char * GetClassName() const { return "DetectorChamber"; }
DetectorChamber() : BaseClass() {
m_ProjectionPlane.origin = HPoint3f(0, 0, 0);
m_ProjectionPlane.direction = HVector3f(0, 0, 1);

View File

@@ -26,6 +26,9 @@ namespace Geant {
class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public Object, public AffineTransform
{
public:
virtual const char* GetClassName() const override { return "Geant.EmitterPrimary"; }
EmitterPrimary();
virtual ~EmitterPrimary();
@@ -44,6 +47,9 @@ class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public Object, publ
class SkyPlaneEmitterPrimary : public EmitterPrimary
{
public:
virtual const char* GetClassName() const override { return "Geant.SkyPlaneEmitterPrimary"; }
SkyPlaneEmitterPrimary();
virtual ~SkyPlaneEmitterPrimary();
@@ -63,6 +69,9 @@ class SkyPlaneEmitterPrimary : public EmitterPrimary
class CylinderEmitterPrimary : public EmitterPrimary
{
public:
virtual const char* GetClassName() const override { return "Geant.CylinderEmitterPrimary"; }
CylinderEmitterPrimary();
virtual ~CylinderEmitterPrimary();
@@ -89,6 +98,9 @@ class CylinderEmitterPrimary : public EmitterPrimary
class QuadMeshEmitterPrimary : public EmitterPrimary
{
public:
virtual const char* GetClassName() const override { return "Geant.QuadMeshEmitterPrimary"; }
QuadMeshEmitterPrimary();
virtual ~QuadMeshEmitterPrimary();

View File

@@ -26,6 +26,7 @@
#ifndef U_GEANTEVENT_H
#define U_GEANTEVENT_H
#include "Core/Object.h"
#include "Core/Types.h"
#include "Core/Vector.h"
#include "Math/Dense.h"
@@ -46,10 +47,12 @@ class SteppingAction;
/// recording the change of momentum and direction at each step boundary.
///////////////////////////////////////////////////////////////////////////////
class GeantEvent {
class GeantEvent : public Object {
public:
virtual const char* GetClassName() const override { return "Geant.GeantEvent"; }
/// A single interaction step along the muon path.
struct Delta {
Scalarf m_Length; ///< step length through the solid

View File

@@ -59,6 +59,8 @@ private:
class Material : public Object {
public:
virtual const char* GetClassName() const override { return "Geant.Material"; }
uLibRefMacro(G4Data,G4Material *)
private:
G4Material *m_G4Data;

View File

@@ -43,6 +43,9 @@ class EmitterPrimary;
class Scene : public Object {
public:
virtual const char* GetClassName() const override { return "Geant.Scene"; }
Scene();
~Scene();

View File

@@ -43,6 +43,9 @@ namespace Geant {
class Solid : public Object {
public:
virtual const char* GetClassName() const override { return "Geant.Solid"; }
Solid();
Solid(const char *name);
virtual ~Solid();
@@ -83,6 +86,9 @@ protected:
class TessellatedSolid : public Solid {
typedef Solid BaseClass;
public:
virtual const char* GetClassName() const override { return "Geant.TessellatedSolid"; }
TessellatedSolid(const char *name);
void SetMesh(TriangleMesh &mesh);
uLibGetMacro(Solid, G4TessellatedSolid *)
@@ -104,6 +110,9 @@ class BoxSolid : public Solid {
typedef Solid BaseClass;
public:
virtual const char* GetClassName() const override { return "Geant.BoxSolid"; }
BoxSolid(const char *name, ContainerBox *box);
virtual G4VSolid* GetG4Solid() const override { return (G4VSolid*)m_Solid; }

View File

@@ -34,7 +34,8 @@ set(SOURCES VoxRaytracer.cpp
QuadMesh.cpp
Dense.cpp
Structured2DGrid.cpp
Structured4DGrid.cpp)
Structured4DGrid.cpp
MathRegistrations.cpp)
set(LIBRARIES ${PACKAGE_LIBPREFIX}Core
Eigen3::Eigen

View File

@@ -48,6 +48,9 @@ class ContainerBox : public AffineTransform, public Object {
typedef AffineTransform BaseClass;
public:
virtual const char * GetClassName() const { return "ContainerBox"; }
/**
* @brief Default constructor.
* Initializes the local transformation with this instance as its parent.

View File

@@ -45,6 +45,9 @@ class Cylinder : public AffineTransform, public Object {
typedef AffineTransform BaseClass;
public:
virtual const char * GetClassName() const { return "Cylinder"; }
/**
* @brief Default constructor.
* Initializes with radius 1 and height 1.

View File

@@ -28,15 +28,18 @@
#ifndef U_GEOMETRY_H
#define U_GEOMETRY_H
#include "Core/Object.h"
#include "Math/Dense.h"
#include "Math/Transform.h"
#include <cmath>
namespace uLib {
class Geometry : public AffineTransform {
class Geometry : public AffineTransform, public Object {
public:
virtual const char * GetClassName() const { return "Geometry"; }
virtual Vector3f ToLinear(const Vector3f& curved_space) const {
return curved_space;
}
@@ -87,6 +90,8 @@ class SphericalGeometry : public Geometry {
public:
SphericalGeometry() {}
virtual const char * GetClassName() const { return "SphericalGeometry"; }
Vector3f ToLinear(const Vector3f& spherical) const {
float r = spherical.x();
float theta = spherical.y();
@@ -109,6 +114,8 @@ class ToroidalGeometry : public Geometry {
public:
ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {}
virtual const char * GetClassName() const { return "ToroidalGeometry"; }
Vector3f ToLinear(const Vector3f& toroidal) const {
float r = toroidal.x();
float theta = toroidal.y();

View File

@@ -0,0 +1,20 @@
#include "Core/ObjectFactory.h"
#include "Math/ContainerBox.h"
#include "Math/Cylinder.h"
#include "Math/Geometry.h"
#include "Math/TriangleMesh.h"
#include "Math/QuadMesh.h"
#include "Math/VoxImage.h"
#include "Math/StructuredData.h"
namespace uLib {
ULIB_REGISTER_OBJECT(ContainerBox)
ULIB_REGISTER_OBJECT(Cylinder)
ULIB_REGISTER_OBJECT(CylindricalGeometry)
ULIB_REGISTER_OBJECT(SphericalGeometry)
ULIB_REGISTER_OBJECT(TriangleMesh)
ULIB_REGISTER_OBJECT(QuadMesh)
ULIB_REGISTER_OBJECT_NAME(VoxImage<Voxel>, "VoxImage")
} // namespace uLib

View File

@@ -36,6 +36,8 @@ class Polydata : public Object {
public:
virtual const char * GetClassName() const { return "Polydata"; }
};

View File

@@ -37,6 +37,9 @@ namespace uLib {
class QuadMesh : public AffineTransform, public Object
{
public:
virtual const char * GetClassName() const { return "QuadMesh"; }
void PrintSelf(std::ostream &o);
/** @brief Adds a point in global coordinates. Stored in local coordinates. */

View File

@@ -40,6 +40,9 @@ namespace uLib {
class TriangleMesh : public AffineTransform, public Object
{
public:
virtual const char * GetClassName() const { return "TriangleMesh"; }
void PrintSelf(std::ostream &o);
/** @brief Adds a point in global coordinates. Stored in local coordinates. */

View File

@@ -46,6 +46,9 @@ namespace Abstract {
class VoxImage : public uLib::StructuredGrid {
public:
virtual const char * GetClassName() const { return "VoxImage"; }
typedef uLib::StructuredGrid BaseClass;
virtual float GetValue(const Vector3i &id) const = 0;

View File

@@ -57,9 +57,12 @@ protected:
} // namespace Abstract
template <typename VoxelT, typename AlgorithmT>
class VoxImageFilter : public Abstract::VoxImageFilter {
class VoxImageFilter : public Abstract::VoxImageFilter, public Object {
public:
virtual const char * GetClassName() const { return "VoxImageFilter"; }
VoxImageFilter(const Vector3i &size);
void Run();

View File

@@ -5,6 +5,7 @@ set(HEADERS uLibVtkInterface.h
vtkQViewport.h
vtkViewport.h
vtkPolydata.h
vtkObjectsContext.h
)
set(SOURCES uLibVtkInterface.cxx
@@ -14,6 +15,7 @@ set(SOURCES uLibVtkInterface.cxx
vtkQViewport.cpp
vtkViewport.cpp
vtkPolydata.cpp
vtkObjectsContext.cpp
)
## Pull in Math VTK wrappers (sets MATH_SOURCES / MATH_HEADERS)

View File

@@ -103,6 +103,10 @@ private:
class PuppetData *d;
};
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,150 @@
#include "vtkObjectsContext.h"
#include "vtkContainerBox.h"
#include "HEP/Detectors/vtkDetectorChamber.h"
#include <vtkAssembly.h>
#include <vtkPropCollection.h>
#include <iostream>
#include <cstring>
namespace uLib {
namespace Vtk {
vtkObjectsContext::vtkObjectsContext(uLib::ObjectsContext *context)
: m_Context(context), m_Assembly(::vtkAssembly::New()) {
this->SetProp(m_Assembly);
if (m_Context) {
Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this, &vtkObjectsContext::OnObjectAdded);
Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this, &vtkObjectsContext::OnObjectRemoved);
this->Synchronize();
}
}
vtkObjectsContext::~vtkObjectsContext() {
for (auto const& [obj, puppet] : m_Puppets) {
delete puppet;
}
m_Assembly->Delete();
}
void vtkObjectsContext::Synchronize() {
if (!m_Context) return;
// 1. Identify objects to add and remove
const auto& objects = m_Context->GetObjects();
std::map<uLib::Object*, bool> currentObjects;
for (auto obj : objects) currentObjects[obj] = true;
// Remove puppets for objects no longer in context
for (auto it = m_Puppets.begin(); it != m_Puppets.end(); ) {
if (currentObjects.find(it->first) == currentObjects.end()) {
it->second->DisconnectRenderer(nullptr); // If we have a ref to a renderer we should disconnect but Puppet doesn't store it easily
// Actually Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer.
// For now we just remove from assembly
vtkPropCollection* props = it->second->GetProps();
props->InitTraversal();
while(vtkProp* prop = props->GetNextProp()) {
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
m_Assembly->RemovePart(p3d);
}
this->PuppetRemoved(it->second);
delete it->second;
it = m_Puppets.erase(it);
} else {
++it;
}
}
// Add puppets for new objects
for (auto obj : objects) {
if (m_Puppets.find(obj) == m_Puppets.end()) {
Puppet* puppet = this->CreatePuppet(obj);
if (puppet) {
m_Puppets[obj] = puppet;
vtkPropCollection* props = puppet->GetProps();
props->InitTraversal();
while(vtkProp* prop = props->GetNextProp()) {
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
m_Assembly->AddPart(p3d);
}
this->PuppetAdded(puppet);
}
}
}
}
void vtkObjectsContext::OnObjectAdded(uLib::Object* obj) {
if (!obj) return;
if (m_Puppets.find(obj) == m_Puppets.end()) {
Puppet* puppet = this->CreatePuppet(obj);
if (puppet) {
m_Puppets[obj] = puppet;
vtkPropCollection* props = puppet->GetProps();
props->InitTraversal();
while(vtkProp* prop = props->GetNextProp()) {
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
m_Assembly->AddPart(p3d);
}
this->PuppetAdded(puppet);
}
}
}
void vtkObjectsContext::OnObjectRemoved(uLib::Object* obj) {
if (!obj) return;
auto it = m_Puppets.find(obj);
if (it != m_Puppets.end()) {
// For now we just remove from assembly.
// Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily.
vtkPropCollection* props = it->second->GetProps();
props->InitTraversal();
while(vtkProp* prop = props->GetNextProp()) {
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
m_Assembly->RemovePart(p3d);
}
this->PuppetRemoved(it->second);
delete it->second;
m_Puppets.erase(it);
}
}
Puppet* vtkObjectsContext::GetPuppet(uLib::Object* obj) {
auto it = m_Puppets.find(obj);
if (it != m_Puppets.end()) return it->second;
return nullptr;
}
void vtkObjectsContext::Update() {
for (auto const& [obj, puppet] : m_Puppets) {
puppet->Update();
}
}
Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
if (!obj) return nullptr;
const char* className = obj->GetClassName();
if (std::strcmp(className, "ContainerBox") == 0) {
return new vtkContainerBox(static_cast<uLib::ContainerBox*>(obj));
} else if (std::strcmp(className, "DetectorChamber") == 0) {
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
}
// Fallback if we don't know the exact class but it might be a context itself
if (auto subCtx = dynamic_cast<uLib::ObjectsContext*>(obj)) {
return new vtkObjectsContext(subCtx);
}
return nullptr;
}
void vtkObjectsContext::PuppetAdded(Puppet* puppet) {
ULIB_SIGNAL_EMIT(vtkObjectsContext::PuppetAdded, puppet);
}
void vtkObjectsContext::PuppetRemoved(Puppet* puppet) {
ULIB_SIGNAL_EMIT(vtkObjectsContext::PuppetRemoved, puppet);
}
} // namespace Vtk
} // namespace uLib

View File

@@ -0,0 +1,54 @@
#ifndef U_VTKOBJECTSCONTEXT_H
#define U_VTKOBJECTSCONTEXT_H
#include <map>
#include "Core/ObjectsContext.h"
#include "uLibVtkInterface.h"
class vtkAssembly;
namespace uLib {
namespace Vtk {
/**
* @brief vtkObjectsContext manages VTK representations (Puppets) for a collection of uLib::Objects.
*/
class vtkObjectsContext : public uLib::Object, public Puppet {
public:
virtual const char* GetClassName() const override { return "vtkObjectsContext"; }
vtkObjectsContext(uLib::ObjectsContext *context);
virtual ~vtkObjectsContext();
/** @brief Synchronizes the VTK puppets with the core ObjectsContext. */
void Synchronize();
/** @brief Returns the puppet associated with a specific core object. */
Puppet* GetPuppet(uLib::Object* obj);
/** @brief Updates all managed puppets. */
virtual void Update() override;
public:
virtual void PuppetAdded(Puppet* puppet);
virtual void PuppetRemoved(Puppet* puppet);
public:
/** @brief Slot called when an object is added to the core context. */
void OnObjectAdded(uLib::Object* obj);
/** @brief Slot called when an object is removed from the core context. */
void OnObjectRemoved(uLib::Object* obj);
protected:
/** @brief Factory method to create a puppet for a core object. */
Puppet* CreatePuppet(uLib::Object* obj);
private:
uLib::ObjectsContext *m_Context;
std::map<uLib::Object*, Puppet*> m_Puppets;
vtkAssembly *m_Assembly;
};
} // namespace Vtk
} // namespace uLib
#endif // U_VTKOBJECTSCONTEXT_H