4 Commits

Author SHA1 Message Date
AndreaRigoni
a8f786d8d1 add context panel 2026-03-21 20:14:29 +00:00
AndreaRigoni
add9d37aea Add Geometries 2026-03-21 19:43:56 +00:00
AndreaRigoni
0bff36f8ba context in core 2026-03-21 16:30:56 +00:00
AndreaRigoni
cd95f16221 fix name in gcompose 2026-03-21 16:30:38 +00:00
23 changed files with 866 additions and 51 deletions

View File

@@ -3,10 +3,16 @@ add_executable(gcompose
src/main.cpp
src/MainWindow.h
src/MainWindow.cpp
src/QViewportPane.h
src/QViewportPane.cpp
src/ViewportPane.h
src/ViewportPane.cpp
src/MainPanel.h
src/MainPanel.cpp
src/ContextPanel.h
src/ContextPanel.cpp
src/ContextModel.h
src/ContextModel.cpp
src/StyleManager.h
src/StyleManager.cpp
)
set_target_properties(gcompose PROPERTIES

View File

@@ -0,0 +1,132 @@
#include "ContextModel.h"
#include <QString>
#include <typeinfo>
#include <cxxabi.h>
#include <functional>
ContextModel::ContextModel(QObject* parent)
: QAbstractItemModel(parent), m_rootContext(nullptr) {}
ContextModel::~ContextModel() {}
void ContextModel::setContext(uLib::ObjectsContext* context) {
beginResetModel();
m_rootContext = context;
endResetModel();
}
QModelIndex ContextModel::index(int row, int column, const QModelIndex& parent) const {
if (!hasIndex(row, column, parent) || !m_rootContext) {
return QModelIndex();
}
if (!parent.isValid()) {
if (row < m_rootContext->GetCount()) {
return createIndex(row, column, m_rootContext->GetObject(row));
}
} else {
uLib::Object* parentObj = static_cast<uLib::Object*>(parent.internalPointer());
uLib::ObjectsContext* parentCtx = dynamic_cast<uLib::ObjectsContext*>(parentObj);
if (parentCtx && row < parentCtx->GetCount()) {
return createIndex(row, column, parentCtx->GetObject(row));
}
}
return QModelIndex();
}
QModelIndex ContextModel::parent(const QModelIndex& child) const {
if (!child.isValid() || !m_rootContext) {
return QModelIndex();
}
uLib::Object* childObj = static_cast<uLib::Object*>(child.internalPointer());
// Finding the parent of childObj is O(N) since there is no parent pointer.
// We just do a recursive search starting from root context.
std::function<uLib::ObjectsContext*(uLib::ObjectsContext*, uLib::Object*)> findParent =
[&findParent](uLib::ObjectsContext* ctx, uLib::Object* target) -> uLib::ObjectsContext* {
for (const auto& obj : ctx->GetObjects()) {
if (obj == target) return ctx;
if (auto subCtx = dynamic_cast<uLib::ObjectsContext*>(obj)) {
if (auto p = findParent(subCtx, target)) return p;
}
}
return nullptr;
};
uLib::ObjectsContext* parentCtx = findParent(m_rootContext, childObj);
if (!parentCtx || parentCtx == m_rootContext) {
return QModelIndex(); // Root items have invalid parent index
}
// Now need to find the row of parentCtx in its own parent Context.
uLib::ObjectsContext* grandParentCtx = findParent(m_rootContext, parentCtx);
if (!grandParentCtx) grandParentCtx = m_rootContext;
int row = -1;
for (size_t i = 0; i < grandParentCtx->GetCount(); ++i) {
if (grandParentCtx->GetObject(i) == parentCtx) {
row = (int)i;
break;
}
}
if (row != -1) {
return createIndex(row, 0, parentCtx);
}
return QModelIndex();
}
int ContextModel::rowCount(const QModelIndex& parent) const {
if (!m_rootContext) return 0;
if (!parent.isValid()) {
return m_rootContext->GetCount();
}
uLib::Object* parentObj = static_cast<uLib::Object*>(parent.internalPointer());
if (auto parentCtx = dynamic_cast<uLib::ObjectsContext*>(parentObj)) {
return parentCtx->GetCount();
}
return 0; // leaf node
}
int ContextModel::columnCount(const QModelIndex& parent) const {
return 1;
}
static QString getDemangledName(const std::type_info& info) {
int status = -4;
char* demangled = abi::__cxa_demangle(info.name(), nullptr, nullptr, &status);
QString res = (status == 0 && demangled) ? QString::fromUtf8(demangled) : QString::fromUtf8(info.name());
if (demangled) free(demangled);
// Remove namespaces
int lastColon = res.lastIndexOf("::");
if (lastColon != -1) {
res = res.mid(lastColon + 2);
}
// Remove "class " prefix if any
if (res.startsWith("class ")) res = res.mid(6);
return res;
}
QVariant ContextModel::data(const QModelIndex& index, int role) const {
if (!index.isValid()) return QVariant();
uLib::Object* obj = static_cast<uLib::Object*>(index.internalPointer());
if (role == Qt::DisplayRole) {
return getDemangledName(typeid(*obj));
}
return QVariant();
}
QVariant ContextModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0) {
return "Object Type";
}
return QVariant();
}

View File

@@ -0,0 +1,26 @@
#ifndef CONTEXT_MODEL_H
#define CONTEXT_MODEL_H
#include <QAbstractItemModel>
#include "Core/ObjectsContext.h"
class ContextModel : public QAbstractItemModel {
Q_OBJECT
public:
explicit ContextModel(QObject* parent = nullptr);
virtual ~ContextModel();
void setContext(uLib::ObjectsContext* context);
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& child) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
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;
private:
uLib::ObjectsContext* m_rootContext;
};
#endif // CONTEXT_MODEL_H

View File

@@ -0,0 +1,43 @@
#include "ContextPanel.h"
#include "ContextModel.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTreeView>
ContextPanel::ContextPanel(QWidget* parent) : QWidget(parent) {
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setSpacing(0);
// Title bar setup
m_titleBar = new QWidget(this);
m_titleBar->setObjectName("PaneTitleBar");
m_titleBar->setFixedHeight(22);
auto* titleLayout = new QHBoxLayout(m_titleBar);
titleLayout->setContentsMargins(5, 0, 5, 0);
m_titleLabel = new QLabel("Context Panel", m_titleBar);
m_titleLabel->setObjectName("TitleLabel");
titleLayout->addWidget(m_titleLabel);
titleLayout->addStretch();
m_layout->addWidget(m_titleBar);
m_treeView = new QTreeView(this);
m_treeView->setObjectName("ContextTree");
m_treeView->setHeaderHidden(false);
m_model = new ContextModel(this);
m_treeView->setModel(m_model);
m_layout->addWidget(m_treeView);
}
ContextPanel::~ContextPanel() {}
void ContextPanel::setContext(uLib::ObjectsContext* context) {
m_model->setContext(context);
m_treeView->expandAll();
}

View File

@@ -0,0 +1,31 @@
#ifndef CONTEXT_PANEL_H
#define CONTEXT_PANEL_H
#include <QWidget>
class QTreeView;
class QVBoxLayout;
class QLabel;
class ContextModel;
namespace uLib {
class ObjectsContext;
}
class ContextPanel : public QWidget {
Q_OBJECT
public:
explicit ContextPanel(QWidget* parent = nullptr);
virtual ~ContextPanel();
void setContext(uLib::ObjectsContext* context);
private:
QVBoxLayout* m_layout;
QWidget* m_titleBar;
QLabel* m_titleLabel;
QTreeView* m_treeView;
ContextModel* m_model;
};
#endif // CONTEXT_PANEL_H

View File

@@ -1,10 +1,15 @@
#include "MainPanel.h"
#include "QViewportPane.h"
#include "ViewportPane.h"
#include "ContextPanel.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
#include <QLabel>
#include <QPushButton>
#include <QMenu>
#include <QAction>
#include <QApplication>
#include "StyleManager.h"
MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
auto* mainLayout = new QVBoxLayout(this);
@@ -13,37 +18,72 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
// 1. Top Menu Panel
auto* menuPanel = new QWidget(this);
menuPanel->setObjectName("MenuPanel");
menuPanel->setFixedHeight(36);
menuPanel->setStyleSheet("background-color: #2b2b2b; border-bottom: 1px solid #111;");
auto* menuLayout = new QHBoxLayout(menuPanel);
menuLayout->setContentsMargins(10, 0, 10, 0);
menuLayout->setSpacing(15);
auto* logo = new QLabel("G-COMPOSE", menuPanel);
logo->setStyleSheet("font-weight: bold; color: #0078d7; font-size: 14px; letter-spacing: 1px;");
logo->setObjectName("LogoLabel");
auto* btnOpen = new QPushButton("Open", menuPanel);
auto* btnSave = new QPushButton("Save", menuPanel);
QString btnStyle = "QPushButton { background: transparent; color: #ccc; border: none; padding: 5px 10px; }"
"QPushButton:hover { background: #3c3c3c; color: white; border-radius: 4px; }";
btnOpen->setStyleSheet(btnStyle);
btnSave->setStyleSheet(btnStyle);
// File Menu Button
auto* btnFile = new QPushButton("File", menuPanel);
btnFile->setObjectName("MenuButton");
auto* fileMenu = new QMenu(btnFile);
fileMenu->addAction("Open", this, &MainPanel::onOpen);
fileMenu->addAction("Save", this, &MainPanel::onSave);
btnFile->setMenu(fileMenu);
// Theme Menu Button
auto* btnTheme = new QPushButton("Theme", menuPanel);
btnTheme->setObjectName("MenuButton");
auto* themeMenu = new QMenu(btnTheme);
themeMenu->addAction("Dark", this, &MainPanel::onDarkTheme);
themeMenu->addAction("Bright", this, &MainPanel::onBrightTheme);
btnTheme->setMenu(themeMenu);
menuLayout->addWidget(logo);
menuLayout->addWidget(btnOpen);
menuLayout->addWidget(btnSave);
menuLayout->addWidget(btnFile);
menuLayout->addWidget(btnTheme);
menuLayout->addStretch();
mainLayout->addWidget(menuPanel);
// 2. Central Splitter Area
m_rootSplitter = new QSplitter(Qt::Horizontal, this);
m_firstPane = new QViewportPane(m_rootSplitter);
m_contextPanel = new ContextPanel(m_rootSplitter);
m_rootSplitter->addWidget(m_contextPanel);
m_firstPane = new ViewportPane(m_rootSplitter);
m_rootSplitter->addWidget(m_firstPane);
// Set initial sizes
QList<int> sizes;
sizes << 200 << 1000;
m_rootSplitter->setSizes(sizes);
mainLayout->addWidget(m_rootSplitter, 1);
}
void MainPanel::setContext(uLib::ObjectsContext* context) {
m_contextPanel->setContext(context);
}
void MainPanel::onOpen() {
// Placeholder for open logic
}
void MainPanel::onSave() {
// Placeholder for save logic
}
void MainPanel::onDarkTheme() {
StyleManager::applyStyle(qApp, "dark");
}
void MainPanel::onBrightTheme() {
StyleManager::applyStyle(qApp, "bright");
}
MainPanel::~MainPanel() {}

View File

@@ -4,7 +4,12 @@
#include <QWidget>
class QSplitter;
class QViewportPane;
class ViewportPane;
class ContextPanel;
namespace uLib {
class ObjectsContext;
}
class MainPanel : public QWidget {
Q_OBJECT
@@ -12,11 +17,19 @@ public:
explicit MainPanel(QWidget* parent = nullptr);
virtual ~MainPanel();
QViewportPane* getFirstPane() const { return m_firstPane; }
void setContext(uLib::ObjectsContext* context);
ViewportPane* getFirstPane() const { return m_firstPane; }
private slots:
void onOpen();
void onSave();
void onDarkTheme();
void onBrightTheme();
private:
QSplitter* m_rootSplitter;
QViewportPane* m_firstPane;
ViewportPane* m_firstPane;
ContextPanel* m_contextPanel;
};
#endif // MAINPANEL_H

View File

@@ -1,6 +1,7 @@
#include "MainWindow.h"
#include <QSplitter>
#include "MainPanel.h"
#include "Core/ObjectsContext.h"
using namespace uLib;
@@ -14,3 +15,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
MainWindow::~MainWindow() {
}
void MainWindow::setContext(uLib::ObjectsContext* context) {
m_panel->setContext(context);
}

View File

@@ -5,10 +5,12 @@
#include <QVTKOpenGLNativeWidget.h>
class MainPanel;
class ViewportPane;
namespace uLib {
namespace Vtk {
}
class ObjectsContext;
}
class MainWindow : public QMainWindow {
@@ -17,6 +19,7 @@ public:
MainWindow(QWidget* parent = nullptr);
virtual ~MainWindow();
void setContext(uLib::ObjectsContext* context);
MainPanel* getPanel() { return m_panel; }
private:

View File

@@ -17,19 +17,19 @@ QViewportPane::QViewportPane(QWidget* parent) : QWidget(parent), m_viewport(null
// Title bar setup
m_titleBar = new QWidget(this);
m_titleBar->setObjectName("PaneTitleBar");
m_titleBar->setFixedHeight(22);
m_titleBar->setStyleSheet("background-color: #333; color: white;");
auto* titleLayout = new QHBoxLayout(m_titleBar);
titleLayout->setContentsMargins(5, 0, 5, 0);
m_titleLabel = new QLabel("Viewport", m_titleBar);
m_titleLabel->setObjectName("TitleLabel");
auto* closeBtn = new QToolButton(m_titleBar);
closeBtn->setObjectName("PaneCloseButton");
closeBtn->setText("X");
closeBtn->setFixedSize(18, 18);
closeBtn->setStyleSheet("QToolButton { border: none; font-weight: bold; background: transparent; color: #ccc; } "
"QToolButton:hover { color: white; background: red; }");
titleLayout->addWidget(m_titleLabel);
titleLayout->addStretch();

View File

@@ -0,0 +1,44 @@
#include "StyleManager.h"
#include <QApplication>
static const QString DARK_THEME = R"(
QWidget#MenuPanel { background-color: #2b2b2b; border-bottom: 1px solid #111; }
QLabel#LogoLabel { font-weight: bold; color: #0078d7; font-size: 14px; letter-spacing: 1px; }
QPushButton#MenuButton { background: transparent; color: #ccc; border: none; padding: 5px 10px; }
QPushButton#MenuButton:hover { background: #3c3c3c; color: white; border-radius: 4px; }
QWidget#PaneTitleBar { background-color: #333; color: white; }
QToolButton#PaneCloseButton { border: none; font-weight: bold; background: transparent; color: #ccc; }
QToolButton#PaneCloseButton:hover { color: white; background: red; }
QMenu { background-color: #2b2b2b; color: white; border: 1px solid #111; }
QMenu::item:selected { background-color: #3c3c3c; }
QTreeView#ContextTree { background-color: #1e1e1e; color: #ccc; border: none; }
QTreeView#ContextTree::item:hover { background-color: #2a2d2e; }
QTreeView#ContextTree::item:selected { background-color: #094771; color: white; }
QHeaderView::section { background-color: #252526; color: #ccc; border: 1px solid #323233; padding: 4px; }
)";
static const QString BRIGHT_THEME = R"(
QWidget#MenuPanel { background-color: #f0f0f0; border-bottom: 1px solid #ccc; }
QLabel#LogoLabel { font-weight: bold; color: #005a9e; font-size: 14px; letter-spacing: 1px; }
QPushButton#MenuButton { background: transparent; color: #333; border: none; padding: 5px 10px; }
QPushButton#MenuButton:hover { background: #d0d0d0; color: black; border-radius: 4px; }
QWidget#PaneTitleBar { background-color: #e0e0e0; color: black; }
QToolButton#PaneCloseButton { border: none; font-weight: bold; background: transparent; color: #666; }
QToolButton#PaneCloseButton:hover { color: white; background: #e81123; }
QMenu { background-color: #f0f0f0; color: black; border: 1px solid #ccc; }
QMenu::item:selected { background-color: #d0d0d0; }
QTreeView#ContextTree { background-color: #ffffff; color: #333; border: none; }
QTreeView#ContextTree::item:hover { background-color: #f2f2f2; }
QTreeView#ContextTree::item:selected { background-color: #0078d7; color: white; }
QHeaderView::section { background-color: #f3f3f3; color: #333; border: 1px solid #ccc; padding: 4px; }
)";
void StyleManager::applyStyle(QApplication* app, const QString& themeName) {
if (!app) return;
if (themeName == "bright") {
app->setStyleSheet(BRIGHT_THEME);
} else {
app->setStyleSheet(DARK_THEME); // default
}
}

View File

@@ -0,0 +1,13 @@
#ifndef STYLEMANAGER_H
#define STYLEMANAGER_H
#include <QString>
class QApplication;
class StyleManager {
public:
static void applyStyle(QApplication* app, const QString& themeName);
};
#endif // STYLEMANAGER_H

View File

@@ -0,0 +1,169 @@
#include "ViewportPane.h"
#include <Vtk/vtkQViewport.h>
#include <Root/QCanvas.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
#include <QMenu>
#include <QAction>
#include <QSplitter>
#include <vtkCamera.h>
ViewportPane::ViewportPane(QWidget* parent) : QWidget(parent), m_viewport(nullptr) {
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setSpacing(0);
// Title bar setup
m_titleBar = new QWidget(this);
m_titleBar->setObjectName("PaneTitleBar");
m_titleBar->setFixedHeight(22);
auto* titleLayout = new QHBoxLayout(m_titleBar);
titleLayout->setContentsMargins(5, 0, 5, 0);
m_titleLabel = new QLabel("Viewport", m_titleBar);
m_titleLabel->setObjectName("TitleLabel");
auto* closeBtn = new QToolButton(m_titleBar);
closeBtn->setObjectName("PaneCloseButton");
closeBtn->setText("X");
closeBtn->setFixedSize(18, 18);
titleLayout->addWidget(m_titleLabel);
titleLayout->addStretch();
titleLayout->addWidget(closeBtn);
m_layout->addWidget(m_titleBar);
m_titleBar->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_titleBar, &QWidget::customContextMenuRequested, this, &ViewportPane::showContextMenu);
connect(closeBtn, &QToolButton::clicked, this, &ViewportPane::onCloseRequested);
addVtkViewport(); // Initialize with a default VTK viewport
}
ViewportPane::~ViewportPane() {}
void ViewportPane::setViewport(QWidget* viewport, const QString& title) {
if (m_viewport) {
m_layout->removeWidget(m_viewport);
delete m_viewport;
}
m_viewport = viewport;
m_titleLabel->setText(title);
m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_layout->addWidget(m_viewport);
}
void ViewportPane::addVtkViewport() {
auto* viewport = new uLib::Vtk::QViewport(this);
setViewport(viewport, "VTK Viewport");
}
void ViewportPane::addRootCanvas() {
auto* canvas = new uLib::Root::QCanvas(this);
setViewport(canvas, "ROOT Canvas");
}
void ViewportPane::onCloseRequested() {
QSplitter* parentSplitter = qobject_cast<QSplitter*>(parentWidget());
if (parentSplitter && parentSplitter->count() > 1) {
deleteLater();
} else {
// Can't close the last viewport in the splitter safely. Re-initialize to default VTK canvas.
addVtkViewport();
}
}
void ViewportPane::showContextMenu(const QPoint& pos) {
QMenu menu(this);
QAction* hSplit = menu.addAction("H split");
QAction* vSplit = menu.addAction("V split");
menu.addSeparator();
bool isVtk = (qobject_cast<uLib::Vtk::QViewport*>(m_viewport) != nullptr);
QAction* changeType = menu.addAction(isVtk ? "Change to ROOT Canvas" : "Change to VTK Viewport");
QAction* selected = menu.exec(m_titleBar->mapToGlobal(pos));
if (selected == hSplit) {
AttemptSplit(Qt::Horizontal);
} else if (selected == vSplit) {
AttemptSplit(Qt::Vertical);
} else if (selected == changeType) {
if (isVtk) {
addRootCanvas();
} else {
addVtkViewport();
}
}
}
void ViewportPane::AttemptSplit(Qt::Orientation orientation) {
QWidget* p = parentWidget();
if (!p) return;
QSplitter* parentSplitter = qobject_cast<QSplitter*>(p);
if (!parentSplitter) return;
ViewportPane* newPane = new ViewportPane();
// 1. Synchronize viewport content and camera (VTK Viewport only for now)
auto* currentVtk = qobject_cast<uLib::Vtk::QViewport*>(m_viewport);
if (currentVtk) {
auto* newVtk = qobject_cast<uLib::Vtk::QViewport*>(newPane->currentViewport());
if (newVtk) {
// Copy puppets
for (auto* puppet : currentVtk->getPuppets()) {
newVtk->AddPuppet(*puppet);
}
// Copy camera
if (currentVtk->GetRenderer() && newVtk->GetRenderer()) {
vtkCamera* currentCam = currentVtk->GetRenderer()->GetActiveCamera();
vtkCamera* newCam = newVtk->GetRenderer()->GetActiveCamera();
if (currentCam && newCam) {
newCam->DeepCopy(currentCam);
}
}
// Sync grid visible and axis
newVtk->SetGridVisible(currentVtk->GetGridVisible());
newVtk->SetGridAxis(currentVtk->GetGridAxis());
}
}
// 2. Adjust for ROOT Canvas if that was the active view
bool isRoot = (qobject_cast<uLib::Root::QCanvas*>(m_viewport) != nullptr);
if (isRoot) {
newPane->addRootCanvas();
}
if (parentSplitter->orientation() == orientation) {
int index = parentSplitter->indexOf(this);
QList<int> sizes = parentSplitter->sizes();
int currentSize = sizes.value(index, 0);
int half = currentSize / 2;
sizes[index] = half;
sizes.insert(index + 1, currentSize - half);
parentSplitter->insertWidget(index + 1, newPane);
parentSplitter->setSizes(sizes);
} else {
int index = parentSplitter->indexOf(this);
QList<int> parentSizes = parentSplitter->sizes();
QSplitter* newSplitter = new QSplitter(orientation);
newSplitter->addWidget(this);
newSplitter->addWidget(newPane);
QList<int> subSizes;
subSizes << 500 << 500;
newSplitter->setSizes(subSizes);
parentSplitter->insertWidget(index, newSplitter);
parentSplitter->setSizes(parentSizes);
}
}

View File

@@ -0,0 +1,34 @@
#ifndef VIEWPORTPANE_H
#define VIEWPORTPANE_H
#include <QWidget>
class QVBoxLayout;
class QLabel;
class ViewportPane : public QWidget {
Q_OBJECT
public:
explicit ViewportPane(QWidget* parent = nullptr);
virtual ~ViewportPane();
void addVtkViewport();
void addRootCanvas();
QWidget* currentViewport() const { return m_viewport; }
private slots:
void onCloseRequested();
void showContextMenu(const QPoint& pos);
private:
void AttemptSplit(Qt::Orientation orientation);
void setViewport(QWidget* viewport, const QString& title);
QVBoxLayout* m_layout;
QWidget* m_titleBar;
QLabel* m_titleLabel;
QWidget* m_viewport;
};
#endif // VIEWPORTPANE_H

View File

@@ -1,7 +1,8 @@
#include <QApplication>
#include "MainWindow.h"
#include "MainPanel.h"
#include "QViewportPane.h"
#include "ViewportPane.h"
#include "StyleManager.h"
#include "Math/ContainerBox.h"
#include <HEP/Geant/Scene.h>
@@ -11,6 +12,8 @@
#include <Vtk/vtkContainerBox.h>
#include <Vtk/vtkQViewport.h>
#include "Core/ObjectsContext.h"
#include <vtkSmartPointer.h>
#include <vtkCubeSource.h>
#include <vtkPolyDataMapper.h>
@@ -26,6 +29,7 @@ using namespace uLib::literals;
int main(int argc, char** argv) {
QApplication app(argc, argv);
StyleManager::applyStyle(&app, "dark");
std::cout << "Starting gcompose Qt application..." << std::endl;
ContainerBox world_box(Vector3f(1, 1, 1));
@@ -35,10 +39,15 @@ int main(int argc, char** argv) {
scene.ConstructWorldBox(world_box.GetSize(), "G4_AIR");
scene.Initialize();
uLib::ObjectsContext globalContext;
globalContext.AddObject(&world_box);
globalContext.AddObject(&scene);
// 2. Initialize MainWindow (contains embedded VTK QViewport)
MainWindow window;
window.setContext(&globalContext);
MainPanel* panel = window.getPanel();
QViewportPane* pane = panel->getFirstPane();
ViewportPane* pane = panel->getFirstPane();
Vtk::QViewport* viewport = qobject_cast<Vtk::QViewport*>(pane->currentViewport());
Vtk::vtkContainerBox vtk_box(&world_box);

View File

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

View File

@@ -0,0 +1,47 @@
#include "Core/ObjectsContext.h"
#include <algorithm>
namespace uLib {
ObjectsContext::ObjectsContext() : Object() {}
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);
this->Updated(); // Signal that the context has been updated
}
}
void ObjectsContext::RemoveObject(Object* obj) {
auto it = std::find(m_objects.begin(), m_objects.end(), obj);
if (it != m_objects.end()) {
m_objects.erase(it);
this->Updated(); // Signal that the context has been updated
}
}
void ObjectsContext::Clear() {
if (!m_objects.empty()) {
m_objects.clear();
this->Updated();
}
}
const std::vector<Object*>& ObjectsContext::GetObjects() const {
return m_objects;
}
size_t ObjectsContext::GetCount() const {
return m_objects.size();
}
Object* ObjectsContext::GetObject(size_t index) const {
if (index < m_objects.size()) {
return m_objects[index];
}
return nullptr;
}
} // namespace uLib

59
src/Core/ObjectsContext.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef U_CORE_OBJECTS_CONTEXT_H
#define U_CORE_OBJECTS_CONTEXT_H
#include "Core/Object.h"
#include <vector>
namespace uLib {
/**
* @brief ObjectsContext represents a collection of Object instances.
*/
class ObjectsContext : public Object {
public:
ObjectsContext();
virtual ~ObjectsContext();
/**
* @brief Adds an object to the context.
* @param obj Pointer to the object to add.
*/
void AddObject(Object* obj);
/**
* @brief Removes an object from the context.
* @param obj Pointer to the object to remove.
*/
void RemoveObject(Object* obj);
/**
* @brief Clears all objects from the context.
*/
void Clear();
/**
* @brief Returns the collection of objects.
* @return Const reference to the vector of object pointers.
*/
const std::vector<Object*>& GetObjects() const;
/**
* @brief Returns the number of objects in the context.
* @return Size of the collection.
*/
size_t GetCount() const;
/**
* @brief Returns an object by index.
* @param index The index of the object.
* @return Pointer to the object or nullptr if index is out of bounds.
*/
Object* GetObject(size_t index) const;
private:
std::vector<Object*> m_objects;
};
} // namespace uLib
#endif // U_CORE_OBJECTS_CONTEXT_H

View File

@@ -77,13 +77,13 @@ public:
* @brief Sets the box origin relative to its coordinate system.
* @param v The origin position vector.
*/
inline void SetOrigin(const Vector3f &v) { m_LocalT.SetPosition(v); }
void SetOrigin(const Vector3f &v) { m_LocalT.SetPosition(v); }
/**
* @brief Gets the box origin relative to its coordinate system.
* @return The origin position vector.
*/
inline Vector3f GetOrigin() const { return m_LocalT.GetPosition(); }
Vector3f GetOrigin() const { return m_LocalT.GetPosition(); }
/**
* @brief Sets the size of the box.
@@ -101,7 +101,7 @@ public:
* @brief Gets the current size (scale) of the box.
* @return The size vector.
*/
inline Vector3f GetSize() const {
Vector3f GetSize() const {
Vector3f s = this->GetScale();
Vector3f ls = m_LocalT.GetScale();
return Vector3f(s(0) * ls(0), s(1) * ls(1), s(2) * ls(2));
@@ -112,7 +112,7 @@ public:
* @param first Index of the first axis (0=X, 1=Y, 2=Z).
* @param second Index of the second axis (0=X, 1=Y, 2=Z).
*/
inline void FlipLocalAxes(int first, int second) {
void FlipLocalAxes(int first, int second) {
m_LocalT.FlipAxes(first, second);
}
@@ -133,7 +133,7 @@ public:
* @param v The local point (4D homogeneous vector).
* @return The transformed point in world space.
*/
inline Vector4f GetWorldPoint(const Vector4f &v) const {
Vector4f GetWorldPoint(const Vector4f &v) const {
return m_LocalT.GetWorldMatrix() * v;
}
@@ -144,7 +144,7 @@ public:
* @param z Z coordinate in local space.
* @return The transformed point in world space.
*/
inline Vector4f GetWorldPoint(const float x, const float y, const float z) {
Vector4f GetWorldPoint(const float x, const float y, const float z) {
return this->GetWorldPoint(Vector4f(x, y, z, 1));
}
@@ -153,7 +153,7 @@ public:
* @param v The world point (4D homogeneous vector).
* @return The transformed point in box-local space.
*/
inline Vector4f GetLocalPoint(const Vector4f &v) const {
Vector4f GetLocalPoint(const Vector4f &v) const {
return m_LocalT.GetWorldMatrix().inverse() * v;
}
@@ -164,7 +164,7 @@ public:
* @param z Z coordinate in world space.
* @return The transformed point in box-local space.
*/
inline Vector4f GetLocalPoint(const float x, const float y, const float z) {
Vector4f GetLocalPoint(const float x, const float y, const float z) {
return this->GetLocalPoint(Vector4f(x, y, z, 1));
}

View File

@@ -30,14 +30,24 @@
#include "Math/Dense.h"
#include "Math/Transform.h"
#include <cmath>
namespace uLib {
class Geometry : public AffineTransform {
public:
virtual Vector3f ToLinear(const Vector3f& curved_space) const {
return curved_space;
}
virtual Vector3f FromLinear(const Vector3f& cartesian_space) const {
return cartesian_space;
}
inline Vector4f GetWorldPoint(const Vector4f v) const {
return this->GetWorldMatrix() * v;
Vector3f lin = ToLinear(Vector3f(v.x(), v.y(), v.z()));
return this->GetWorldMatrix() * Vector4f(lin.x(), lin.y(), lin.z(), v.w());
}
inline Vector4f GetWorldPoint(const float x, const float y, const float z) {
@@ -45,7 +55,9 @@ public:
}
inline Vector4f GetLocalPoint(const Vector4f v) const {
return this->GetWorldMatrix().inverse() * v;
Vector4f loc_lin = this->GetWorldMatrix().inverse() * v;
Vector3f curv = FromLinear(Vector3f(loc_lin.x(), loc_lin.y(), loc_lin.z()));
return Vector4f(curv.x(), curv.y(), curv.z(), loc_lin.w());
}
inline Vector4f GetLocalPoint(const float x, const float y, const float z) {
@@ -53,6 +65,73 @@ public:
}
};
class CylindricalGeometry : public Geometry {
public:
CylindricalGeometry() {}
Vector3f ToLinear(const Vector3f& cylindrical) const {
return Vector3f(cylindrical.x() * std::cos(cylindrical.y()),
cylindrical.x() * std::sin(cylindrical.y()),
cylindrical.z());
}
Vector3f FromLinear(const Vector3f& linear) const {
float r = std::sqrt(linear.x() * linear.x() + linear.y() * linear.y());
float phi = std::atan2(linear.y(), linear.x());
return Vector3f(r, phi, linear.z());
}
};
class SphericalGeometry : public Geometry {
public:
SphericalGeometry() {}
Vector3f ToLinear(const Vector3f& spherical) const {
float r = spherical.x();
float theta = spherical.y();
float phi = spherical.z();
return Vector3f(r * std::sin(theta) * std::cos(phi),
r * std::sin(theta) * std::sin(phi),
r * std::cos(theta));
}
Vector3f FromLinear(const Vector3f& linear) const {
float r = linear.norm();
float theta = (r == 0.0f) ? 0.0f : std::acos(linear.z() / r);
float phi = std::atan2(linear.y(), linear.x());
return Vector3f(r, theta, phi);
}
};
class ToroidalGeometry : public Geometry {
public:
ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {}
Vector3f ToLinear(const Vector3f& toroidal) const {
float r = toroidal.x();
float theta = toroidal.y();
float phi = toroidal.z();
return Vector3f((m_Rtor + r * std::cos(theta)) * std::cos(phi),
(m_Rtor + r * std::cos(theta)) * std::sin(phi),
r * std::sin(theta));
}
Vector3f FromLinear(const Vector3f& linear) const {
float phi = std::atan2(linear.y(), linear.x());
float r_xy = std::sqrt(linear.x() * linear.x() + linear.y() * linear.y());
float delta_r = r_xy - m_Rtor;
float z = linear.z();
float r = std::sqrt(delta_r * delta_r + z * z);
float theta = std::atan2(z, delta_r);
return Vector3f(r, theta, phi);
}
private:
float m_Rtor;
};
}

View File

@@ -81,12 +81,12 @@ public:
Eigen::Affine3f& GetTransform() { return m_T; }
inline AffineTransform *GetParent() const { return this->m_Parent; }
AffineTransform *GetParent() const { return this->m_Parent; }
inline void SetParent(AffineTransform *name) { this->m_Parent = name; }
void SetParent(AffineTransform *name) { this->m_Parent = name; }
inline void SetMatrix (Matrix4f mat) { m_T.matrix() = mat; }
inline Matrix4f GetMatrix() const { return m_T.matrix(); }
void SetMatrix (Matrix4f mat) { m_T.matrix() = mat; }
Matrix4f GetMatrix() const { return m_T.matrix(); }
Matrix4f GetWorldMatrix() const
{
@@ -94,45 +94,45 @@ public:
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
}
inline void SetPosition(const Vector3f v) { this->m_T.translation() = v; }
void SetPosition(const Vector3f v) { this->m_T.translation() = v; }
inline Vector3f GetPosition() const { return this->m_T.translation(); }
Vector3f GetPosition() const { return this->m_T.translation(); }
inline void SetRotation(const Matrix3f m) { this->m_T.linear() = m; }
void SetRotation(const Matrix3f m) { this->m_T.linear() = m; }
inline Matrix3f GetRotation() const { return this->m_T.rotation(); }
Matrix3f GetRotation() const { return this->m_T.rotation(); }
inline void Translate(const Vector3f v) { this->m_T.pretranslate(v); }
void Translate(const Vector3f v) { this->m_T.pretranslate(v); }
inline void Scale(const Vector3f v) { this->m_T.scale(v); }
void Scale(const Vector3f v) { this->m_T.scale(v); }
inline Vector3f GetScale() const {
Vector3f GetScale() const {
return Vector3f(m_T.linear().col(0).norm(),
m_T.linear().col(1).norm(),
m_T.linear().col(2).norm());
}
inline void Rotate(const Matrix3f m) { this->m_T.rotate(m); }
void Rotate(const Matrix3f m) { this->m_T.rotate(m); }
inline void Rotate(const float angle, Vector3f axis)
void Rotate(const float angle, Vector3f axis)
{
axis.normalize(); // prehaps not necessary ( see eigens )
Eigen::AngleAxisf ax(angle,axis);
this->m_T.rotate(Eigen::Quaternion<float>(ax));
}
inline void Rotate(const Vector3f euler_axis) {
void Rotate(const Vector3f euler_axis) {
float angle = euler_axis.norm();
Rotate(angle,euler_axis);
}
inline void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); }
void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); }
inline void QuaternionRotate(const Vector4f q)
void QuaternionRotate(const Vector4f q)
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); }
inline void EulerYZYRotate(const Vector3f e) {
void EulerYZYRotate(const Vector3f e) {
Matrix3f mat;
mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY())
* Eigen::AngleAxisf(e.y(), Vector3f::UnitZ())
@@ -140,7 +140,7 @@ public:
m_T.rotate(mat);
}
inline void FlipAxes(int first, int second)
void FlipAxes(int first, int second)
{
Matrix3f mat = Matrix3f::Identity();
mat.col(first).swap(mat.col(second));

View File

@@ -162,6 +162,36 @@ int main()
{ // test parent-child relationship
ContainerBox Parent;
Parent.SetPosition(Vector3f(1,1,1));
Parent.Scale(Vector3f(2,2,2));
ContainerBox Child;
Child.SetParent(&Parent);
Child.SetPosition(Vector3f(0,0,0));
HPoint3f pt = Child.GetLocalPoint(HPoint3f(0,0,0));
HPoint3f wp = Child.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(0,0,0)) );
pt = HPoint3f(1,1,1);
wp = Child.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(3,3,3)) );
Parent.Rotate(Vector3f(M_PI,0,0));
pt = HPoint3f(1,1,1);
wp = Child.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(3,-1,-1)) );
Child.Rotate(Vector3f(M_PI,0,0));
pt = HPoint3f(1,1,1);
wp = Child.GetWorldPoint(pt);
TEST0( Vector4f0(wp - HPoint3f(3,3,3)) );
}
END_TESTING;
}

View File

@@ -92,6 +92,36 @@ int main()
// CYLINDRICAL GEOMETRY TESTING
{
CylindricalGeometry cyl;
Vector3f cyl_pt(5.0f, M_PI_2, 3.0f);
Vector3f lin = cyl.ToLinear(cyl_pt);
TEST0( Vector4f0(lin.homogeneous() - HPoint3f(0.0f, 5.0f, 3.0f)) );
Vector3f recovered = cyl.FromLinear(lin);
TEST0( Vector4f0(recovered.homogeneous() - cyl_pt.homogeneous()) );
}
// SPHERICAL GEOMETRY TESTING
{
SphericalGeometry sph;
Vector3f sph_pt(5.0f, M_PI_2, M_PI);
Vector3f lin = sph.ToLinear(sph_pt);
TEST0( Vector4f0(lin.homogeneous() - HPoint3f(-5.0f, 0.0f, 0.0f)) );
Vector3f recovered = sph.FromLinear(Vector3f(-5.0f, 0.0f, 0.0f));
TEST0( Vector4f0(recovered.homogeneous() - sph_pt.homogeneous()) );
}
// TOROIDAL GEOMETRY TESTING
{
ToroidalGeometry tor(10.0f);
Vector3f tor_pt(1.0f, M_PI_2, M_PI);
Vector3f lin = tor.ToLinear(tor_pt);
TEST0( Vector4f0(lin.homogeneous() - HPoint3f(-10.0f, 0.0f, 1.0f)) );
Vector3f recovered = tor.FromLinear(Vector3f(-10.0f, 0.0f, 1.0f));
TEST0( Vector4f0(recovered.homogeneous() - tor_pt.homogeneous()) );
}
END_TESTING;
}