Compare commits
3 Commits
andrea-alg
...
93e5602562
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93e5602562 | ||
|
|
09859e872c | ||
|
|
2a6dcf02bd |
7
.agents/rules/micromamba.md
Normal file
7
.agents/rules/micromamba.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
build in build directory using always micromamba "mutom" env.
|
||||||
|
build with make flag -j$(nproc).
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ endif()
|
|||||||
project(uLib)
|
project(uLib)
|
||||||
|
|
||||||
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
||||||
option(USE_CUDA "Enable CUDA support" ON)
|
option(USE_CUDA "Enable CUDA support" OFF)
|
||||||
if(USE_CUDA)
|
if(USE_CUDA)
|
||||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -allow-unsupported-compiler")
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -allow-unsupported-compiler")
|
||||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr")
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr")
|
||||||
@@ -115,7 +115,7 @@ set(Boost_USE_MULTITHREADED ON)
|
|||||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||||
message(STATUS "CMAKE_PREFIX_PATH is ${CMAKE_PREFIX_PATH}")
|
message(STATUS "CMAKE_PREFIX_PATH is ${CMAKE_PREFIX_PATH}")
|
||||||
|
|
||||||
find_package(HDF5 REQUIRED CONFIG)
|
find_package(HDF5 REQUIRED)
|
||||||
|
|
||||||
find_package(Boost 1.45.0 COMPONENTS program_options serialization unit_test_framework REQUIRED)
|
find_package(Boost 1.45.0 COMPONENTS program_options serialization unit_test_framework REQUIRED)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Vtk/uLibVtkInterface.h"
|
#include "Vtk/uLibVtkInterface.h"
|
||||||
#include "Math/Units.h"
|
#include "Math/Units.h"
|
||||||
#include "Math/Dense.h"
|
#include "Math/Dense.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Qt {
|
namespace Qt {
|
||||||
@@ -15,8 +16,21 @@ PropertyWidgetBase::PropertyWidgetBase(PropertyBase* prop, QWidget* parent)
|
|||||||
: QWidget(parent), m_BaseProperty(prop) {
|
: QWidget(parent), m_BaseProperty(prop) {
|
||||||
m_Layout = new QHBoxLayout(this);
|
m_Layout = new QHBoxLayout(this);
|
||||||
m_Layout->setContentsMargins(4, 2, 4, 2);
|
m_Layout->setContentsMargins(4, 2, 4, 2);
|
||||||
m_Label = new QLabel(QString::fromStdString(prop->GetName()), this);
|
|
||||||
m_Label->setMinimumWidth(100);
|
std::string unit = prop->GetUnits();
|
||||||
|
QString labelText = QString::fromStdString(prop->GetName());
|
||||||
|
if (!unit.empty()) {
|
||||||
|
auto dim = Settings::Instance().IdentifyDimension(unit);
|
||||||
|
std::string pref = Settings::Instance().GetPreferredUnit(dim);
|
||||||
|
if (!pref.empty()) {
|
||||||
|
labelText += " [" + QString::fromStdString(pref) + "]";
|
||||||
|
} else {
|
||||||
|
labelText += " [" + QString::fromStdString(unit) + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Label = new QLabel(labelText, this);
|
||||||
|
m_Label->setMinimumWidth(120);
|
||||||
m_Layout->addWidget(m_Label);
|
m_Layout->addWidget(m_Label);
|
||||||
}
|
}
|
||||||
PropertyWidgetBase::~PropertyWidgetBase() {
|
PropertyWidgetBase::~PropertyWidgetBase() {
|
||||||
@@ -115,9 +129,6 @@ void UnitLineEdit::updateText() {
|
|||||||
s += ".0";
|
s += ".0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_Suffix.isEmpty()) {
|
|
||||||
s += " " + m_Suffix;
|
|
||||||
}
|
|
||||||
setText(s);
|
setText(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +140,12 @@ void UnitLineEdit::setIntegerOnly(bool integerOnly) {
|
|||||||
DoublePropertyWidget::DoublePropertyWidget(Property<double>* prop, QWidget* parent)
|
DoublePropertyWidget::DoublePropertyWidget(Property<double>* prop, QWidget* parent)
|
||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
m_Edit = new UnitLineEdit(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
QString units = QString::fromStdString(prop->GetUnits());
|
std::string unit = prop->GetUnits();
|
||||||
if (!units.isEmpty()) {
|
if (!unit.empty()) {
|
||||||
double factor = 1.0;
|
auto dim = Settings::Instance().IdentifyDimension(unit);
|
||||||
parseWithUnits("1 " + units, &factor);
|
std::string pref = Settings::Instance().GetPreferredUnit(dim);
|
||||||
m_Edit->setUnits(units, factor);
|
double factor = Settings::Instance().GetUnitFactor(pref);
|
||||||
|
m_Edit->setUnits(QString::fromStdString(pref), factor);
|
||||||
}
|
}
|
||||||
m_Edit->setValue(prop->Get());
|
m_Edit->setValue(prop->Get());
|
||||||
m_Layout->addWidget(m_Edit, 1);
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
@@ -146,11 +158,12 @@ DoublePropertyWidget::DoublePropertyWidget(Property<double>* prop, QWidget* pare
|
|||||||
FloatPropertyWidget::FloatPropertyWidget(Property<float>* prop, QWidget* parent)
|
FloatPropertyWidget::FloatPropertyWidget(Property<float>* prop, QWidget* parent)
|
||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
m_Edit = new UnitLineEdit(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
QString units = QString::fromStdString(prop->GetUnits());
|
std::string unit = prop->GetUnits();
|
||||||
if (!units.isEmpty()) {
|
if (!unit.empty()) {
|
||||||
double factor = 1.0;
|
auto dim = Settings::Instance().IdentifyDimension(unit);
|
||||||
parseWithUnits("1 " + units, &factor);
|
std::string pref = Settings::Instance().GetPreferredUnit(dim);
|
||||||
m_Edit->setUnits(units, factor);
|
double factor = Settings::Instance().GetUnitFactor(pref);
|
||||||
|
m_Edit->setUnits(QString::fromStdString(pref), factor);
|
||||||
}
|
}
|
||||||
m_Edit->setValue(prop->Get());
|
m_Edit->setValue(prop->Get());
|
||||||
m_Layout->addWidget(m_Edit, 1);
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
@@ -164,11 +177,12 @@ IntPropertyWidget::IntPropertyWidget(Property<int>* prop, QWidget* parent)
|
|||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
m_Edit = new UnitLineEdit(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
m_Edit->setIntegerOnly(true);
|
m_Edit->setIntegerOnly(true);
|
||||||
QString units = QString::fromStdString(prop->GetUnits());
|
std::string unit = prop->GetUnits();
|
||||||
if (!units.isEmpty()) {
|
if (!unit.empty()) {
|
||||||
double factor = 1.0;
|
auto dim = Settings::Instance().IdentifyDimension(unit);
|
||||||
parseWithUnits("1 " + units, &factor);
|
std::string pref = Settings::Instance().GetPreferredUnit(dim);
|
||||||
m_Edit->setUnits(units, factor);
|
double factor = Settings::Instance().GetUnitFactor(pref);
|
||||||
|
m_Edit->setUnits(QString::fromStdString(pref), factor);
|
||||||
}
|
}
|
||||||
m_Edit->setValue(prop->Get());
|
m_Edit->setValue(prop->Get());
|
||||||
m_Layout->addWidget(m_Edit, 1);
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
@@ -211,6 +225,26 @@ StringPropertyWidget::StringPropertyWidget(Property<std::string>* prop, QWidget*
|
|||||||
}
|
}
|
||||||
StringPropertyWidget::~StringPropertyWidget() {}
|
StringPropertyWidget::~StringPropertyWidget() {}
|
||||||
|
|
||||||
|
class GroupHeaderWidget : public QWidget {
|
||||||
|
public:
|
||||||
|
GroupHeaderWidget(const QString& name, QWidget* parent = nullptr) : QWidget(parent) {
|
||||||
|
auto* layout = new QVBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 8, 0, 4);
|
||||||
|
auto* line = new QFrame(this);
|
||||||
|
line->setFrameShape(QFrame::HLine);
|
||||||
|
line->setFrameShadow(QFrame::Sunken);
|
||||||
|
line->setStyleSheet("color: #555;");
|
||||||
|
layout->addWidget(line);
|
||||||
|
auto* label = new QLabel(name, this);
|
||||||
|
QFont font = label->font();
|
||||||
|
font.setBold(true);
|
||||||
|
font.setPointSize(font.pointSize() + 1);
|
||||||
|
label->setFont(font);
|
||||||
|
label->setStyleSheet("color: #aaa; text-transform: uppercase;");
|
||||||
|
layout->addWidget(label);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class EnumPropertyWidget : public PropertyWidgetBase {
|
class EnumPropertyWidget : public PropertyWidgetBase {
|
||||||
PropertyBase* m_Prop;
|
PropertyBase* m_Prop;
|
||||||
QComboBox* m_Combo;
|
QComboBox* m_Combo;
|
||||||
@@ -305,26 +339,51 @@ void PropertyEditor::setObject(::uLib::Object* obj, bool displayOnly) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Group properties by their group string
|
||||||
|
std::map<std::string, std::vector<::uLib::PropertyBase*>> groupedProps;
|
||||||
|
std::vector<std::string> groupOrder;
|
||||||
|
|
||||||
for (auto* prop : *props) {
|
for (auto* prop : *props) {
|
||||||
// Priority 1: Check if it provides enum labels
|
std::string group = prop->GetGroup();
|
||||||
if (!prop->GetEnumLabels().empty()) {
|
if (groupedProps.find(group) == groupedProps.end()) {
|
||||||
m_ContainerLayout->addWidget(new EnumPropertyWidget(prop, m_Container));
|
groupOrder.push_back(group);
|
||||||
continue;
|
}
|
||||||
|
groupedProps[group].push_back(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& groupName : groupOrder) {
|
||||||
|
if (!groupName.empty()) {
|
||||||
|
m_ContainerLayout->addWidget(new GroupHeaderWidget(QString::fromStdString(groupName), m_Container));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 2: Standard factory lookup
|
for (auto* prop : groupedProps[groupName]) {
|
||||||
auto it = m_Factories.find(prop->GetTypeIndex());
|
QWidget* widget = nullptr;
|
||||||
if (it != m_Factories.end()) {
|
|
||||||
QWidget* widget = it->second(prop, m_Container);
|
// Priority 1: Check if it provides enum labels
|
||||||
m_ContainerLayout->addWidget(widget);
|
if (!prop->GetEnumLabels().empty()) {
|
||||||
} else {
|
widget = new EnumPropertyWidget(prop, m_Container);
|
||||||
// Debug info for unknown types
|
} else {
|
||||||
std::cout << "PropertyEditor: No factory for " << prop->GetName()
|
// Priority 2: Standard factory lookup
|
||||||
<< " (Type: " << prop->GetTypeName() << ")" << std::endl;
|
auto it = m_Factories.find(prop->GetTypeIndex());
|
||||||
|
if (it != m_Factories.end()) {
|
||||||
|
widget = it->second(prop, m_Container);
|
||||||
|
} else {
|
||||||
|
// Debug info for unknown types
|
||||||
|
std::cout << "PropertyEditor: No factory for " << prop->GetQualifiedName()
|
||||||
|
<< " (Type: " << prop->GetTypeName() << ")" << std::endl;
|
||||||
|
|
||||||
QWidget* fallback = new PropertyWidgetBase(prop, m_Container);
|
widget = new PropertyWidgetBase(prop, m_Container);
|
||||||
fallback->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
|
widget->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
|
||||||
m_ContainerLayout->addWidget(fallback);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget) {
|
||||||
|
if (!groupName.empty()) {
|
||||||
|
// Indent grouped properties
|
||||||
|
widget->setContentsMargins(16, 0, 0, 0);
|
||||||
|
}
|
||||||
|
m_ContainerLayout->addWidget(widget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_ContainerLayout->addStretch(1);
|
m_ContainerLayout->addStretch(1);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
#include "Core/Signal.h"
|
#include "Core/Signal.h"
|
||||||
#include "Math/Dense.h"
|
#include "Math/Dense.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Qt {
|
namespace Qt {
|
||||||
@@ -93,18 +94,24 @@ class VectorPropertyWidget : public PropertyWidgetBase {
|
|||||||
public:
|
public:
|
||||||
VectorPropertyWidget(Property<VecT>* prop, QWidget* parent = nullptr)
|
VectorPropertyWidget(Property<VecT>* prop, QWidget* parent = nullptr)
|
||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
QString units = QString::fromStdString(prop->GetUnits());
|
|
||||||
|
std::string unit = prop->GetUnits();
|
||||||
double factor = 1.0;
|
double factor = 1.0;
|
||||||
if (!units.isEmpty()) {
|
QString prefSuffix;
|
||||||
parseWithUnits("1 " + units, &factor);
|
if (!unit.empty()) {
|
||||||
|
auto dim = Settings::Instance().IdentifyDimension(unit);
|
||||||
|
std::string pref = Settings::Instance().GetPreferredUnit(dim);
|
||||||
|
factor = Settings::Instance().GetUnitFactor(pref);
|
||||||
|
prefSuffix = QString::fromStdString(pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < Size; ++i) {
|
for (int i = 0; i < Size; ++i) {
|
||||||
m_Edits[i] = new UnitLineEdit(this);
|
m_Edits[i] = new UnitLineEdit(this);
|
||||||
if (std::is_integral<typename VecT::Scalar>::value) {
|
if (std::is_integral<typename VecT::Scalar>::value) {
|
||||||
m_Edits[i]->setIntegerOnly(true);
|
m_Edits[i]->setIntegerOnly(true);
|
||||||
}
|
}
|
||||||
if (!units.isEmpty()) {
|
if (!prefSuffix.isEmpty()) {
|
||||||
m_Edits[i]->setUnits(units, factor);
|
m_Edits[i]->setUnits(prefSuffix, factor);
|
||||||
}
|
}
|
||||||
m_Layout->addWidget(m_Edits[i], 1);
|
m_Layout->addWidget(m_Edits[i], 1);
|
||||||
|
|
||||||
|
|||||||
75
app/gcompose/src/Settings.h
Normal file
75
app/gcompose/src/Settings.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef GCOMPOSE_SETTINGS_H
|
||||||
|
#define GCOMPOSE_SETTINGS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include "Math/Units.h"
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Qt {
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
public:
|
||||||
|
static Settings& Instance() {
|
||||||
|
static Settings instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Dimension {
|
||||||
|
Length,
|
||||||
|
Angle,
|
||||||
|
Energy,
|
||||||
|
Time,
|
||||||
|
Dimensionless
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetPreferredUnit(Dimension dim, const std::string& unit) {
|
||||||
|
m_PreferredUnits[dim] = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPreferredUnit(Dimension dim) const {
|
||||||
|
auto it = m_PreferredUnits.find(dim);
|
||||||
|
if (it != m_PreferredUnits.end()) return it->second;
|
||||||
|
|
||||||
|
switch(dim) {
|
||||||
|
case Length: return "mm";
|
||||||
|
case Angle: return "deg";
|
||||||
|
case Energy: return "MeV";
|
||||||
|
case Time: return "ns";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double GetUnitFactor(const std::string& unit) const {
|
||||||
|
if (unit == "m") return CLHEP::meter;
|
||||||
|
if (unit == "cm") return CLHEP::centimeter;
|
||||||
|
if (unit == "mm") return CLHEP::millimeter;
|
||||||
|
if (unit == "um") return CLHEP::micrometer;
|
||||||
|
if (unit == "deg") return CLHEP::degree;
|
||||||
|
if (unit == "rad") return CLHEP::radian;
|
||||||
|
if (unit == "ns") return CLHEP::nanosecond;
|
||||||
|
if (unit == "s") return CLHEP::second;
|
||||||
|
if (unit == "ms") return CLHEP::millisecond;
|
||||||
|
if (unit == "MeV") return CLHEP::megaelectronvolt;
|
||||||
|
if (unit == "GeV") return CLHEP::gigaelectronvolt;
|
||||||
|
if (unit == "eV") return CLHEP::electronvolt;
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dimension IdentifyDimension(const std::string& unit) const {
|
||||||
|
if (unit == "m" || unit == "cm" || unit == "mm" || unit == "um" || unit == "nm") return Length;
|
||||||
|
if (unit == "deg" || unit == "rad") return Angle;
|
||||||
|
if (unit == "MeV" || unit == "GeV" || unit == "eV" || unit == "keV" || unit == "TeV") return Energy;
|
||||||
|
if (unit == "ns" || unit == "s" || unit == "ms" || unit == "us") return Time;
|
||||||
|
return Dimensionless;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings() {}
|
||||||
|
std::map<Dimension, std::string> m_PreferredUnits;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Qt
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -46,23 +46,25 @@ ViewportPane::ViewportPane(QWidget* parent) : QWidget(parent), m_viewport(nullpt
|
|||||||
|
|
||||||
m_layout->addWidget(m_titleBar);
|
m_layout->addWidget(m_titleBar);
|
||||||
|
|
||||||
// Main horizontal container for viewport and display panel
|
// Main area with splitter for viewport and display panel
|
||||||
QWidget* mainArea = new QWidget(this);
|
m_areaSplitter = new QSplitter(Qt::Horizontal, this);
|
||||||
QHBoxLayout* hLayout = new QHBoxLayout(mainArea);
|
m_areaSplitter->setObjectName("ViewportAreaSplitter");
|
||||||
hLayout->setContentsMargins(0, 0, 0, 0);
|
m_layout->addWidget(m_areaSplitter, 1);
|
||||||
hLayout->setSpacing(0);
|
|
||||||
m_layout->addWidget(mainArea);
|
|
||||||
|
|
||||||
// Viewport will be added here via setViewport
|
// Viewport will be added here via setViewport
|
||||||
m_viewport = new uLib::Vtk::QViewport(mainArea);
|
m_viewport = new uLib::Vtk::QViewport(m_areaSplitter);
|
||||||
hLayout->addWidget(m_viewport);
|
m_areaSplitter->addWidget(m_viewport);
|
||||||
|
|
||||||
// Display Panel (Overlay/Slide-out)
|
// Display Panel (Overlay/Slide-out)
|
||||||
m_displayPanel = new QFrame(mainArea);
|
m_displayPanel = new QFrame(m_areaSplitter);
|
||||||
m_displayPanel->setObjectName("DisplayPropertiesPanel");
|
m_displayPanel->setObjectName("DisplayPropertiesPanel");
|
||||||
m_displayPanel->setFixedWidth(250);
|
m_displayPanel->setMinimumWidth(150);
|
||||||
m_displayPanel->hide();
|
m_displayPanel->hide();
|
||||||
|
|
||||||
|
m_areaSplitter->addWidget(m_displayPanel);
|
||||||
|
m_areaSplitter->setStretchFactor(0, 1);
|
||||||
|
m_areaSplitter->setStretchFactor(1, 0);
|
||||||
|
|
||||||
QVBoxLayout* panelLayout = new QVBoxLayout(m_displayPanel);
|
QVBoxLayout* panelLayout = new QVBoxLayout(m_displayPanel);
|
||||||
panelLayout->setContentsMargins(5, 5, 5, 5);
|
panelLayout->setContentsMargins(5, 5, 5, 5);
|
||||||
|
|
||||||
@@ -72,8 +74,6 @@ ViewportPane::ViewportPane(QWidget* parent) : QWidget(parent), m_viewport(nullpt
|
|||||||
|
|
||||||
m_displayEditor = new uLib::Qt::PropertyEditor(m_displayPanel);
|
m_displayEditor = new uLib::Qt::PropertyEditor(m_displayPanel);
|
||||||
panelLayout->addWidget(m_displayEditor);
|
panelLayout->addWidget(m_displayEditor);
|
||||||
|
|
||||||
hLayout->addWidget(m_displayPanel);
|
|
||||||
|
|
||||||
connect(m_toggleBtn, &QPushButton::toggled, this, &ViewportPane::toggleDisplayPanel);
|
connect(m_toggleBtn, &QPushButton::toggled, this, &ViewportPane::toggleDisplayPanel);
|
||||||
connect(m_titleBar, &QWidget::customContextMenuRequested, this, &ViewportPane::showContextMenu);
|
connect(m_titleBar, &QWidget::customContextMenuRequested, this, &ViewportPane::showContextMenu);
|
||||||
@@ -85,7 +85,15 @@ ViewportPane::ViewportPane(QWidget* parent) : QWidget(parent), m_viewport(nullpt
|
|||||||
ViewportPane::~ViewportPane() {}
|
ViewportPane::~ViewportPane() {}
|
||||||
|
|
||||||
void ViewportPane::toggleDisplayPanel() {
|
void ViewportPane::toggleDisplayPanel() {
|
||||||
m_displayPanel->setVisible(m_toggleBtn->isChecked());
|
bool visible = m_toggleBtn->isChecked();
|
||||||
|
m_displayPanel->setVisible(visible);
|
||||||
|
if (visible && m_areaSplitter->sizes().value(1, 0) == 0) {
|
||||||
|
QList<int> sizes = m_areaSplitter->sizes();
|
||||||
|
int total = sizes[0] + sizes[1];
|
||||||
|
sizes[1] = 250;
|
||||||
|
sizes[0] = total - 250;
|
||||||
|
m_areaSplitter->setSizes(sizes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportPane::setObject(uLib::Object* obj) {
|
void ViewportPane::setObject(uLib::Object* obj) {
|
||||||
@@ -107,15 +115,14 @@ void ViewportPane::setObject(uLib::Object* obj) {
|
|||||||
|
|
||||||
void ViewportPane::setViewport(QWidget* viewport, const QString& title) {
|
void ViewportPane::setViewport(QWidget* viewport, const QString& title) {
|
||||||
if (m_viewport) {
|
if (m_viewport) {
|
||||||
m_viewport->parentWidget()->layout()->removeWidget(m_viewport);
|
|
||||||
delete m_viewport;
|
delete m_viewport;
|
||||||
}
|
}
|
||||||
m_viewport = viewport;
|
m_viewport = viewport;
|
||||||
m_titleLabel->setText(title);
|
m_titleLabel->setText(title);
|
||||||
|
|
||||||
m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
auto* mainAreaLayout = static_cast<QHBoxLayout*>(m_displayPanel->parentWidget()->layout());
|
m_areaSplitter->insertWidget(0, m_viewport);
|
||||||
mainAreaLayout->insertWidget(0, m_viewport);
|
m_areaSplitter->setStretchFactor(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportPane::addVtkViewport() {
|
void ViewportPane::addVtkViewport() {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace uLib {
|
|||||||
namespace Qt { class PropertyEditor; }
|
namespace Qt { class PropertyEditor; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QSplitter;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ private:
|
|||||||
QVBoxLayout* m_layout;
|
QVBoxLayout* m_layout;
|
||||||
QWidget* m_titleBar;
|
QWidget* m_titleBar;
|
||||||
QLabel* m_titleLabel;
|
QLabel* m_titleLabel;
|
||||||
|
QSplitter* m_areaSplitter;
|
||||||
QWidget* m_viewport;
|
QWidget* m_viewport;
|
||||||
|
|
||||||
// Display Properties Overlay
|
// Display Properties Overlay
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ const std::vector<PropertyBase*>& Object::GetProperties() const {
|
|||||||
|
|
||||||
PropertyBase* Object::GetProperty(const std::string& name) const {
|
PropertyBase* Object::GetProperty(const std::string& name) const {
|
||||||
for (auto* p : d->m_Properties) {
|
for (auto* p : d->m_Properties) {
|
||||||
if (p->GetName() == name) return p;
|
if (p->GetName() == name || p->GetQualifiedName() == name) return p;
|
||||||
}
|
}
|
||||||
for (auto* p : d->m_DynamicProperties) {
|
for (auto* p : d->m_DynamicProperties) {
|
||||||
if (p->GetName() == name) return p;
|
if (p->GetName() == name || p->GetQualifiedName() == name) return p;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace uLib {
|
|||||||
/**
|
/**
|
||||||
* @brief ObjectsContext represents a collection of Object instances.
|
* @brief ObjectsContext represents a collection of Object instances.
|
||||||
*/
|
*/
|
||||||
class ObjectsContext : public Object {
|
class ObjectsContext : virtual public Object {
|
||||||
public:
|
public:
|
||||||
ObjectsContext();
|
ObjectsContext();
|
||||||
virtual ~ObjectsContext();
|
virtual ~ObjectsContext();
|
||||||
|
|||||||
@@ -2,11 +2,16 @@
|
|||||||
#define U_CORE_PROPERTY_H
|
#define U_CORE_PROPERTY_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <typeindex> // Added
|
#include <typeindex> // Added
|
||||||
#include <boost/serialization/nvp.hpp>
|
#include <boost/serialization/nvp.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/type_traits/is_class.hpp>
|
||||||
|
#include <boost/mpl/bool.hpp>
|
||||||
|
#include <boost/serialization/serialization.hpp>
|
||||||
#include "Core/Archives.h"
|
#include "Core/Archives.h"
|
||||||
#include "Core/Signal.h"
|
#include "Core/Signal.h"
|
||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
@@ -29,6 +34,12 @@ public:
|
|||||||
static std::vector<std::string> empty;
|
static std::vector<std::string> empty;
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
virtual const std::string& GetGroup() const = 0;
|
||||||
|
virtual void SetGroup(const std::string& group) = 0;
|
||||||
|
std::string GetQualifiedName() const {
|
||||||
|
if (GetGroup().empty()) return GetName();
|
||||||
|
return GetGroup() + "." + GetName();
|
||||||
|
}
|
||||||
|
|
||||||
// Signal support
|
// Signal support
|
||||||
signals:
|
signals:
|
||||||
@@ -51,16 +62,16 @@ template <typename T>
|
|||||||
class Property : public PropertyBase {
|
class Property : public PropertyBase {
|
||||||
public:
|
public:
|
||||||
// PROXY: Use an existing variable as back-end storage
|
// PROXY: Use an existing variable as back-end storage
|
||||||
Property(Object* owner, const std::string& name, T* valuePtr, const std::string& units = "")
|
Property(Object* owner, const std::string& name, T* valuePtr, const std::string& units = "", const std::string& group = "")
|
||||||
: m_owner(owner), m_name(name), m_units(units), m_value(valuePtr), m_own(false) {
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(valuePtr), m_own(false) {
|
||||||
if (m_owner) {
|
if (m_owner) {
|
||||||
m_owner->RegisterProperty(this);
|
m_owner->RegisterProperty(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MANAGED: Create and own internal storage
|
// MANAGED: Create and own internal storage
|
||||||
Property(Object* owner, const std::string& name, const T& defaultValue = T(), const std::string& units = "")
|
Property(Object* owner, const std::string& name, const T& defaultValue = T(), const std::string& units = "", const std::string& group = "")
|
||||||
: m_owner(owner), m_name(name), m_units(units), m_value(new T(defaultValue)), m_own(true) {
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(new T(defaultValue)), m_own(true) {
|
||||||
if (m_owner) {
|
if (m_owner) {
|
||||||
m_owner->RegisterProperty(this);
|
m_owner->RegisterProperty(this);
|
||||||
}
|
}
|
||||||
@@ -76,6 +87,8 @@ public:
|
|||||||
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(T)); }
|
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(T)); }
|
||||||
virtual const std::string& GetUnits() const override { return m_units; }
|
virtual const std::string& GetUnits() const override { return m_units; }
|
||||||
virtual void SetUnits(const std::string& units) override { m_units = units; }
|
virtual void SetUnits(const std::string& units) override { m_units = units; }
|
||||||
|
virtual const std::string& GetGroup() const override { return m_group; }
|
||||||
|
virtual void SetGroup(const std::string& group) override { m_group = group; }
|
||||||
|
|
||||||
|
|
||||||
std::string GetValueAsString() const override {
|
std::string GetValueAsString() const override {
|
||||||
@@ -124,9 +137,15 @@ public:
|
|||||||
void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
|
|
||||||
|
virtual void Updated() override {
|
||||||
|
PropertyBase::Updated();
|
||||||
|
this->PropertyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_units;
|
std::string m_units;
|
||||||
|
std::string m_group;
|
||||||
T* m_value;
|
T* m_value;
|
||||||
bool m_own;
|
bool m_own;
|
||||||
Object* m_owner;
|
Object* m_owner;
|
||||||
@@ -149,8 +168,8 @@ typedef Property<Bool_t> BoolProperty;
|
|||||||
*/
|
*/
|
||||||
class EnumProperty : public Property<int> {
|
class EnumProperty : public Property<int> {
|
||||||
public:
|
public:
|
||||||
EnumProperty(Object* owner, const std::string& name, int* valuePtr, const std::vector<std::string>& labels, const std::string& units = "")
|
EnumProperty(Object* owner, const std::string& name, int* valuePtr, const std::vector<std::string>& labels, const std::string& units = "", const std::string& group = "")
|
||||||
: Property<int>(owner, name, valuePtr, units), m_Labels(labels) {}
|
: Property<int>(owner, name, valuePtr, units, group), m_Labels(labels) {}
|
||||||
|
|
||||||
const std::vector<std::string>& GetEnumLabels() const override { return m_Labels; }
|
const std::vector<std::string>& GetEnumLabels() const override { return m_Labels; }
|
||||||
const char* GetTypeName() const override { return "Enum"; }
|
const char* GetTypeName() const override { return "Enum"; }
|
||||||
@@ -209,11 +228,20 @@ public:
|
|||||||
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
|
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
|
||||||
m_Object(obj) {}
|
m_Object(obj) {}
|
||||||
|
|
||||||
|
std::string GetCurrentGroup() const {
|
||||||
|
std::string group;
|
||||||
|
for (const auto& g : m_GroupStack) {
|
||||||
|
if (!group.empty()) group += ".";
|
||||||
|
group += g;
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
// Core logic: encounter HRP -> Create Dynamic Property
|
// Core logic: encounter HRP -> Create Dynamic Property
|
||||||
template<class T>
|
template<class T>
|
||||||
void save_override(const boost::serialization::hrp<T> &t) {
|
void save_override(const boost::serialization::hrp<T> &t) {
|
||||||
if (m_Object) {
|
if (m_Object) {
|
||||||
Property<T>* p = new Property<T>(m_Object, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "");
|
Property<T>* p = new Property<T>(m_Object, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
m_Object->RegisterDynamicProperty(p);
|
m_Object->RegisterDynamicProperty(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +249,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
void save_override(const boost::serialization::hrp_enum<T> &t) {
|
void save_override(const boost::serialization::hrp_enum<T> &t) {
|
||||||
if (m_Object) {
|
if (m_Object) {
|
||||||
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "");
|
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
m_Object->RegisterDynamicProperty(p);
|
m_Object->RegisterDynamicProperty(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,11 +257,24 @@ public:
|
|||||||
// Handle standard NVPs by recursing (important for base classes)
|
// Handle standard NVPs by recursing (important for base classes)
|
||||||
template<class T>
|
template<class T>
|
||||||
void save_override(const boost::serialization::nvp<T> &t) {
|
void save_override(const boost::serialization::nvp<T> &t) {
|
||||||
boost::archive::detail::common_oarchive<property_register_archive>::save_override(t.const_value());
|
if (t.name()) m_GroupStack.push_back(t.name());
|
||||||
|
this->save_helper(t.const_value(), typename boost::is_class<T>::type());
|
||||||
|
if (t.name()) m_GroupStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore everything else
|
// Recursion for nested classes, ignore primitives
|
||||||
template<class T> void save_override(const T &t) {}
|
template<class T>
|
||||||
|
void save_override(const T &t) {
|
||||||
|
this->save_helper(t, typename boost::is_class<T>::type());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::true_) {
|
||||||
|
boost::serialization::serialize_adl(*this, const_cast<T&>(t), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::false_) {}
|
||||||
|
|
||||||
// Required attribute overrides for common_oarchive
|
// Required attribute overrides for common_oarchive
|
||||||
void save_override(const boost::archive::object_id_type & t) {}
|
void save_override(const boost::archive::object_id_type & t) {}
|
||||||
@@ -244,6 +285,9 @@ public:
|
|||||||
void save_override(const boost::archive::class_id_reference_type & t) {}
|
void save_override(const boost::archive::class_id_reference_type & t) {}
|
||||||
void save_override(const boost::archive::class_name_type & t) {}
|
void save_override(const boost::archive::class_name_type & t) {}
|
||||||
void save_override(const boost::archive::tracking_type & t) {}
|
void save_override(const boost::archive::tracking_type & t) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_GroupStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ set( TESTS
|
|||||||
VectorMetaAllocatorTest
|
VectorMetaAllocatorTest
|
||||||
PropertyTypesTest
|
PropertyTypesTest
|
||||||
HRPTest
|
HRPTest
|
||||||
|
PropertyGroupingTest
|
||||||
MutexTest
|
MutexTest
|
||||||
ThreadsTest
|
ThreadsTest
|
||||||
OpenMPTest
|
OpenMPTest
|
||||||
|
|||||||
78
src/Core/testing/PropertyGroupingTest.cpp
Normal file
78
src/Core/testing/PropertyGroupingTest.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cassert>
|
||||||
|
#include "Core/Object.h"
|
||||||
|
#include "Core/Property.h"
|
||||||
|
|
||||||
|
using namespace uLib;
|
||||||
|
|
||||||
|
struct Nested {
|
||||||
|
float x = 1.0f;
|
||||||
|
float y = 2.0f;
|
||||||
|
|
||||||
|
ULIB_SERIALIZE_ACCESS
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int version) {
|
||||||
|
ar & HRP(x);
|
||||||
|
ar & HRP(y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GroupObject : public Object {
|
||||||
|
uLibTypeMacro(GroupObject, Object)
|
||||||
|
public:
|
||||||
|
Nested position;
|
||||||
|
Nested orientation;
|
||||||
|
float weight = 50.0f;
|
||||||
|
|
||||||
|
ULIB_SERIALIZE_ACCESS
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int version) {
|
||||||
|
ar & boost::serialization::make_nvp("Position", position);
|
||||||
|
ar & boost::serialization::make_nvp("Orientation", orientation);
|
||||||
|
ar & HRP(weight);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "Testing Property Grouping..." << std::endl;
|
||||||
|
|
||||||
|
GroupObject obj;
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(obj);
|
||||||
|
|
||||||
|
auto props = obj.GetProperties();
|
||||||
|
std::cout << "Registered " << props.size() << " properties." << std::endl;
|
||||||
|
|
||||||
|
for (auto* p : props) {
|
||||||
|
std::cout << "Prop: " << p->GetName()
|
||||||
|
<< " Group: " << p->GetGroup()
|
||||||
|
<< " Qualified: " << p->GetQualifiedName() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if nested properties are registered
|
||||||
|
PropertyBase* p1 = obj.GetProperty("Position.x");
|
||||||
|
PropertyBase* p2 = obj.GetProperty("Position.y");
|
||||||
|
PropertyBase* p3 = obj.GetProperty("Orientation.x");
|
||||||
|
PropertyBase* p4 = obj.GetProperty("Orientation.y");
|
||||||
|
PropertyBase* p5 = obj.GetProperty("weight");
|
||||||
|
|
||||||
|
assert(p1 != nullptr && "Position.x not found");
|
||||||
|
assert(p2 != nullptr && "Position.y not found");
|
||||||
|
assert(p3 != nullptr && "Orientation.x not found");
|
||||||
|
assert(p4 != nullptr && "Orientation.y not found");
|
||||||
|
assert(p5 != nullptr && "weight not found");
|
||||||
|
|
||||||
|
assert(p1->GetGroup() == "Position");
|
||||||
|
assert(p2->GetGroup() == "Position");
|
||||||
|
assert(p3->GetGroup() == "Orientation");
|
||||||
|
assert(p4->GetGroup() == "Orientation");
|
||||||
|
assert(p5->GetGroup() == "");
|
||||||
|
|
||||||
|
assert(p1->GetQualifiedName() == "Position.x");
|
||||||
|
assert(p5->GetQualifiedName() == "weight");
|
||||||
|
|
||||||
|
std::cout << "Property Grouping Tests PASSED!" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ class G4Event;
|
|||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Geant {
|
namespace Geant {
|
||||||
|
|
||||||
class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public Object, public AffineTransform
|
class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public AffineTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ namespace uLib {
|
|||||||
*/
|
*/
|
||||||
class Assembly : public ObjectsContext, public AffineTransform {
|
class Assembly : public ObjectsContext, public AffineTransform {
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(Assembly, ObjectsContext, AffineTransform)
|
||||||
virtual const char *GetClassName() const override { return "Assembly"; }
|
virtual const char *GetClassName() const override { return "Assembly"; }
|
||||||
|
|
||||||
Assembly();
|
Assembly();
|
||||||
|
|||||||
@@ -44,16 +44,17 @@ namespace uLib {
|
|||||||
* that defines the box's specific origin and size relative to its own
|
* that defines the box's specific origin and size relative to its own
|
||||||
* coordinate system.
|
* coordinate system.
|
||||||
*/
|
*/
|
||||||
class ContainerBox : public AffineTransform, public Object {
|
class ContainerBox : public AffineTransform {
|
||||||
|
|
||||||
typedef AffineTransform BaseClass;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(ContainerBox, AffineTransform)
|
||||||
|
|
||||||
|
virtual const char * GetClassName() const override { return "ContainerBox"; }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// PROPERTIES //
|
// PROPERTIES //
|
||||||
Property<Vector3f> p_Size;
|
Vector3f Size;
|
||||||
Property<Vector3f> p_Origin;
|
Vector3f Origin;
|
||||||
virtual const char * GetClassName() const { return "ContainerBox"; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor.
|
* @brief Default constructor.
|
||||||
@@ -61,10 +62,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
ContainerBox()
|
ContainerBox()
|
||||||
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
||||||
p_Size(this, "Size", Vector3f(1.0f, 1.0f, 1.0f)),
|
Size(1.0f, 1.0f, 1.0f),
|
||||||
p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) {
|
Origin(0.0f, 0.0f, 0.0f) {
|
||||||
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,11 +74,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
ContainerBox(const Vector3f &size)
|
ContainerBox(const Vector3f &size)
|
||||||
: m_LocalT(this),
|
: m_LocalT(this),
|
||||||
p_Size(this, "Size", size),
|
Size(size),
|
||||||
p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) {
|
Origin(0.0f, 0.0f, 0.0f) {
|
||||||
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
this->Sync();
|
||||||
this->SetSize(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,13 +85,21 @@ public:
|
|||||||
* @param copy The ContainerBox instance to copy from.
|
* @param copy The ContainerBox instance to copy from.
|
||||||
*/
|
*/
|
||||||
ContainerBox(const ContainerBox ©)
|
ContainerBox(const ContainerBox ©)
|
||||||
: m_LocalT(copy.m_LocalT), // Copy local transform state
|
: m_LocalT(this), // Reset parent to the new object
|
||||||
AffineTransform(copy),
|
AffineTransform(copy),
|
||||||
p_Size(this, "Size", copy.p_Size),
|
Size(copy.Size),
|
||||||
p_Origin(this, "Origin", copy.p_Origin) {
|
Origin(copy.Origin) {
|
||||||
m_LocalT.SetParent(this); // Reset parent to the new object
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
this->Sync();
|
||||||
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serialization template for property registration and persistence.
|
||||||
|
*/
|
||||||
|
template <class ArchiveT>
|
||||||
|
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||||
|
ar & HRP(Size);
|
||||||
|
ar & HRP(Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,7 +107,7 @@ public:
|
|||||||
* @param v The origin position vector.
|
* @param v The origin position vector.
|
||||||
*/
|
*/
|
||||||
void SetOrigin(const Vector3f &v) {
|
void SetOrigin(const Vector3f &v) {
|
||||||
p_Origin = v;
|
Origin = v;
|
||||||
m_LocalT.SetPosition(v);
|
m_LocalT.SetPosition(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +123,7 @@ public:
|
|||||||
* @param v The size vector (width, height, depth).
|
* @param v The size vector (width, height, depth).
|
||||||
*/
|
*/
|
||||||
void SetSize(const Vector3f &v) {
|
void SetSize(const Vector3f &v) {
|
||||||
p_Size = v;
|
Size = v;
|
||||||
Vector3f pos = this->GetOrigin();
|
Vector3f pos = this->GetOrigin();
|
||||||
m_LocalT = AffineTransform(this); // regenerate local transform
|
m_LocalT = AffineTransform(this); // regenerate local transform
|
||||||
m_LocalT.Scale(v);
|
m_LocalT.Scale(v);
|
||||||
@@ -194,26 +202,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Translate using transformation chain */
|
/** Translate using transformation chain */
|
||||||
using BaseClass::Translate;
|
using AffineTransform::Translate;
|
||||||
|
|
||||||
/** Rotate using transformation chain */
|
/** Rotate using transformation chain */
|
||||||
using BaseClass::Rotate;
|
using AffineTransform::Rotate;
|
||||||
|
|
||||||
/** Scale using transformation chain */
|
/** Scale using transformation chain */
|
||||||
using BaseClass::Scale;
|
using AffineTransform::Scale;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
// signal to emit when the box is updated //
|
/** Signal emitted when properties change */
|
||||||
virtual void Updated() override { ULIB_SIGNAL_EMIT(ContainerBox::Updated); }
|
virtual void Updated() override {
|
||||||
|
this->Sync();
|
||||||
private slots:
|
ULIB_SIGNAL_EMIT(ContainerBox::Updated);
|
||||||
void SyncSize() {
|
|
||||||
this->SetSize(p_Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncOrigin() {
|
private:
|
||||||
this->SetOrigin(p_Origin);
|
/** Synchronizes internal transformation with properties */
|
||||||
|
void Sync() {
|
||||||
|
this->SetOrigin(Origin);
|
||||||
|
this->SetSize(Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,17 @@ namespace uLib {
|
|||||||
* The cylinder orientation is defined by the Axis property (0=X, 1=Y, 2=Z).
|
* The cylinder orientation is defined by the Axis property (0=X, 1=Y, 2=Z).
|
||||||
* By default, it is aligned with the Y axis (Axis=1).
|
* By default, it is aligned with the Y axis (Axis=1).
|
||||||
*/
|
*/
|
||||||
class Cylinder : public AffineTransform, public Object {
|
class Cylinder : public AffineTransform {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uLibTypeMacro(Cylinder, Object)
|
uLibTypeMacro(Cylinder, AffineTransform)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PROPERTIES
|
||||||
|
*/
|
||||||
|
float Radius;
|
||||||
|
float Height;
|
||||||
|
int Axis;
|
||||||
|
|
||||||
virtual const char * GetClassName() const override { return "Cylinder"; }
|
virtual const char * GetClassName() const override { return "Cylinder"; }
|
||||||
|
|
||||||
@@ -51,7 +58,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) {
|
Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) {
|
||||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +67,7 @@ public:
|
|||||||
Cylinder(float radius, float height, int axis = 1)
|
Cylinder(float radius, float height, int axis = 1)
|
||||||
: m_LocalT(this), Radius(radius), Height(height), Axis(axis) {
|
: m_LocalT(this), Radius(radius), Height(height), Axis(axis) {
|
||||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +76,7 @@ public:
|
|||||||
Cylinder(const Cylinder ©)
|
Cylinder(const Cylinder ©)
|
||||||
: m_LocalT(this), AffineTransform(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) {
|
: m_LocalT(this), AffineTransform(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) {
|
||||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
this->UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,7 +92,7 @@ public:
|
|||||||
/** Sets the radius of the cylinder */
|
/** Sets the radius of the cylinder */
|
||||||
inline void SetRadius(float r) {
|
inline void SetRadius(float r) {
|
||||||
Radius = r;
|
Radius = r;
|
||||||
UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the radius of the cylinder */
|
/** Gets the radius of the cylinder */
|
||||||
@@ -94,7 +101,7 @@ public:
|
|||||||
/** Sets the height of the cylinder */
|
/** Sets the height of the cylinder */
|
||||||
inline void SetHeight(float h) {
|
inline void SetHeight(float h) {
|
||||||
Height = h;
|
Height = h;
|
||||||
UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the height of the cylinder */
|
/** Gets the height of the cylinder */
|
||||||
@@ -103,7 +110,7 @@ public:
|
|||||||
/** Sets the main axis (0=X, 1=Y, 2=Z) */
|
/** Sets the main axis (0=X, 1=Y, 2=Z) */
|
||||||
inline void SetAxis(int axis) {
|
inline void SetAxis(int axis) {
|
||||||
Axis = axis;
|
Axis = axis;
|
||||||
UpdateLocalMatrix();
|
this->Sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the main axis */
|
/** Gets the main axis */
|
||||||
@@ -157,25 +164,33 @@ public:
|
|||||||
return Vector3f(r, theta, h);
|
return Vector3f(r, theta, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Translate using transformation chain */
|
||||||
|
using AffineTransform::Translate;
|
||||||
|
|
||||||
|
/** Rotate using transformation chain */
|
||||||
|
using AffineTransform::Rotate;
|
||||||
|
|
||||||
|
/** Scale using transformation chain */
|
||||||
|
using AffineTransform::Scale;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/** Signal emitted when properties change */
|
/** Signal emitted when properties change */
|
||||||
virtual void Updated() override {
|
virtual void Updated() override {
|
||||||
this->UpdateLocalMatrix();
|
this->Sync();
|
||||||
ULIB_SIGNAL_EMIT(Cylinder::Updated);
|
ULIB_SIGNAL_EMIT(Cylinder::Updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Recalculates the internal local matrix based on dimensions and axis */
|
/** Synchronizes internal transformation with properties */
|
||||||
void UpdateLocalMatrix() {
|
void Sync() {
|
||||||
m_LocalT = AffineTransform(this);
|
m_LocalT = AffineTransform(this);
|
||||||
if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius));
|
if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius));
|
||||||
else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius));
|
else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius));
|
||||||
else m_LocalT.Scale(Vector3f(Radius, Radius, Height));
|
else m_LocalT.Scale(Vector3f(Radius, Radius, Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
float Radius;
|
|
||||||
float Height;
|
private:
|
||||||
int Axis;
|
|
||||||
AffineTransform m_LocalT;
|
AffineTransform m_LocalT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,11 @@
|
|||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
class Geometry : public AffineTransform, public Object {
|
class Geometry : public AffineTransform {
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(Geometry, AffineTransform)
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "Geometry"; }
|
virtual const char * GetClassName() const override { return "Geometry"; }
|
||||||
|
|
||||||
virtual Vector3f ToLinear(const Vector3f& curved_space) const {
|
virtual Vector3f ToLinear(const Vector3f& curved_space) const {
|
||||||
return curved_space;
|
return curved_space;
|
||||||
@@ -70,6 +71,7 @@ public:
|
|||||||
|
|
||||||
class CylindricalGeometry : public Geometry {
|
class CylindricalGeometry : public Geometry {
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(CylindricalGeometry, Geometry)
|
||||||
CylindricalGeometry() {}
|
CylindricalGeometry() {}
|
||||||
|
|
||||||
Vector3f ToLinear(const Vector3f& cylindrical) const {
|
Vector3f ToLinear(const Vector3f& cylindrical) const {
|
||||||
@@ -88,9 +90,10 @@ public:
|
|||||||
|
|
||||||
class SphericalGeometry : public Geometry {
|
class SphericalGeometry : public Geometry {
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(SphericalGeometry, Geometry)
|
||||||
SphericalGeometry() {}
|
SphericalGeometry() {}
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "SphericalGeometry"; }
|
virtual const char * GetClassName() const override { return "SphericalGeometry"; }
|
||||||
|
|
||||||
Vector3f ToLinear(const Vector3f& spherical) const {
|
Vector3f ToLinear(const Vector3f& spherical) const {
|
||||||
float r = spherical.x();
|
float r = spherical.x();
|
||||||
@@ -112,9 +115,10 @@ public:
|
|||||||
|
|
||||||
class ToroidalGeometry : public Geometry {
|
class ToroidalGeometry : public Geometry {
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(ToroidalGeometry, Geometry)
|
||||||
ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {}
|
ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {}
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "ToroidalGeometry"; }
|
virtual const char * GetClassName() const override { return "ToroidalGeometry"; }
|
||||||
|
|
||||||
Vector3f ToLinear(const Vector3f& toroidal) const {
|
Vector3f ToLinear(const Vector3f& toroidal) const {
|
||||||
float r = toroidal.x();
|
float r = toroidal.x();
|
||||||
|
|||||||
@@ -34,11 +34,12 @@
|
|||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
class QuadMesh : public AffineTransform, public Object
|
class QuadMesh : public AffineTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(QuadMesh, AffineTransform)
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "QuadMesh"; }
|
virtual const char * GetClassName() const override { return "QuadMesh"; }
|
||||||
|
|
||||||
void PrintSelf(std::ostream &o);
|
void PrintSelf(std::ostream &o);
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#define U_TRANSFORM_H
|
#define U_TRANSFORM_H
|
||||||
|
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
#include "Math/Units.h"
|
||||||
#include "Math/Dense.h"
|
#include "Math/Dense.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -59,27 +60,65 @@ namespace uLib {
|
|||||||
///////// AFFINE TRANSFORM WRAPPER //////////////////////////////////////////
|
///////// AFFINE TRANSFORM WRAPPER //////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class AffineTransform {
|
class AffineTransform : virtual public Object {
|
||||||
|
public:
|
||||||
|
uLibTypeMacro(AffineTransform, Object)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Grouped transformation parameters for property-based control.
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
Vector3f Position = Vector3f::Zero();
|
||||||
|
Vector3f Orientation = Vector3f::Zero();
|
||||||
|
Vector3f Scale = Vector3f::Ones();
|
||||||
|
|
||||||
|
template <class ArchiveT>
|
||||||
|
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||||
|
ar & HRPU(Position, "mm");
|
||||||
|
ar & HRPU(Orientation, "deg");
|
||||||
|
ar & HRP(Scale);
|
||||||
|
}
|
||||||
|
} Transform;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Eigen::Affine3f m_T;
|
Eigen::Affine3f m_T;
|
||||||
AffineTransform *m_Parent;
|
AffineTransform *m_Parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AffineTransform() :
|
AffineTransform() :
|
||||||
m_T(Matrix4f::Identity()),
|
m_T(Matrix4f::Identity()),
|
||||||
m_Parent(NULL)
|
m_Parent(NULL)
|
||||||
{}
|
{
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~AffineTransform() {}
|
virtual ~AffineTransform() {}
|
||||||
|
|
||||||
AffineTransform(AffineTransform *parent) :
|
AffineTransform(AffineTransform *parent) :
|
||||||
m_T(Matrix4f::Identity()),
|
m_T(Matrix4f::Identity()),
|
||||||
m_Parent(parent)
|
m_Parent(parent)
|
||||||
{}
|
{
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
AffineTransform(const AffineTransform ©) :
|
AffineTransform(const AffineTransform ©) :
|
||||||
m_T(copy.m_T),
|
m_T(copy.m_T),
|
||||||
m_Parent(copy.m_Parent)
|
m_Parent(copy.m_Parent),
|
||||||
{}
|
Transform(copy.Transform)
|
||||||
|
{
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registration of properties in groups.
|
||||||
|
*/
|
||||||
|
template <class ArchiveT>
|
||||||
|
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||||
|
ar & boost::serialization::make_nvp("Transform", Transform);
|
||||||
|
}
|
||||||
|
|
||||||
Eigen::Affine3f& GetTransform() { return m_T; }
|
Eigen::Affine3f& GetTransform() { return m_T; }
|
||||||
|
|
||||||
@@ -87,7 +126,11 @@ public:
|
|||||||
|
|
||||||
void SetParent(AffineTransform *name) { this->m_Parent = name; }
|
void SetParent(AffineTransform *name) { this->m_Parent = name; }
|
||||||
|
|
||||||
void SetMatrix (Matrix4f mat) { m_T.matrix() = mat; }
|
void SetMatrix (Matrix4f mat) {
|
||||||
|
m_T.matrix() = mat;
|
||||||
|
this->UpdatePropertiesFromMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4f GetMatrix() const { return m_T.matrix(); }
|
Matrix4f GetMatrix() const { return m_T.matrix(); }
|
||||||
|
|
||||||
Matrix4f GetWorldMatrix() const
|
Matrix4f GetWorldMatrix() const
|
||||||
@@ -96,32 +139,51 @@ public:
|
|||||||
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
|
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPosition(const Vector3f v) { this->m_T.translation() = v; }
|
void SetPosition(const Vector3f v) {
|
||||||
|
this->Transform.Position = v;
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
Vector3f GetPosition() const { return this->m_T.translation(); }
|
Vector3f GetPosition() const { return this->Transform.Position; }
|
||||||
|
|
||||||
void SetRotation(const Matrix3f m) { this->m_T.linear() = m; }
|
void SetRotation(const Matrix3f m) {
|
||||||
|
this->m_T.linear() = m;
|
||||||
|
this->UpdatePropertiesFromMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
Matrix3f GetRotation() const { return this->m_T.rotation(); }
|
Matrix3f GetRotation() const { return this->m_T.rotation(); }
|
||||||
|
|
||||||
void Translate(const Vector3f v) { this->m_T.translate(v); }
|
void Translate(const Vector3f v) {
|
||||||
|
this->Transform.Position += v;
|
||||||
void Scale(const Vector3f v) { this->m_T.scale(v); }
|
this->Sync();
|
||||||
|
|
||||||
Vector3f GetScale() const {
|
|
||||||
return Vector3f(m_T.linear().col(0).norm(),
|
|
||||||
m_T.linear().col(1).norm(),
|
|
||||||
m_T.linear().col(2).norm());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scale(const Vector3f v) {
|
||||||
|
this->Transform.Scale = this->Transform.Scale.cwiseProduct(v);
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
void Rotate(const Matrix3f m) { this->m_T.rotate(m); }
|
Vector3f GetScale() const { return this->Transform.Scale; }
|
||||||
|
|
||||||
|
void SetOrientation(const Vector3f v) {
|
||||||
|
this->Transform.Orientation = v;
|
||||||
|
this->Sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f GetOrientation() const { return this->Transform.Orientation; }
|
||||||
|
|
||||||
|
|
||||||
|
void Rotate(const Matrix3f m) {
|
||||||
|
this->m_T.rotate(m);
|
||||||
|
this->UpdatePropertiesFromMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
void Rotate(const float angle, Vector3f axis)
|
void Rotate(const float angle, Vector3f axis)
|
||||||
{
|
{
|
||||||
axis.normalize(); // prehaps not necessary ( see eigens )
|
axis.normalize();
|
||||||
Eigen::AngleAxisf ax(angle,axis);
|
Eigen::AngleAxisf ax(angle,axis);
|
||||||
this->m_T.rotate(Eigen::Quaternion<float>(ax));
|
this->m_T.rotate(Eigen::Quaternion<float>(ax));
|
||||||
|
this->UpdatePropertiesFromMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rotate(const Vector3f euler_axis) {
|
void Rotate(const Vector3f euler_axis) {
|
||||||
@@ -129,17 +191,14 @@ public:
|
|||||||
Rotate(angle,euler_axis);
|
Rotate(angle,euler_axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); }
|
void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); this->UpdatePropertiesFromMatrix(); }
|
||||||
|
|
||||||
void QuaternionRotate(const Vector4f q)
|
void QuaternionRotate(const Vector4f q)
|
||||||
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); }
|
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); this->UpdatePropertiesFromMatrix(); }
|
||||||
|
|
||||||
void EulerYZYRotate(const Vector3f e) {
|
void EulerYZYRotate(const Vector3f e) {
|
||||||
Matrix3f mat;
|
this->Transform.Orientation = e;
|
||||||
mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY())
|
this->Sync();
|
||||||
* Eigen::AngleAxisf(e.y(), Vector3f::UnitZ())
|
|
||||||
* Eigen::AngleAxisf(e.z(), Vector3f::UnitY());
|
|
||||||
m_T.rotate(mat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlipAxes(int first, int second)
|
void FlipAxes(int first, int second)
|
||||||
@@ -147,7 +206,61 @@ public:
|
|||||||
Matrix3f mat = Matrix3f::Identity();
|
Matrix3f mat = Matrix3f::Identity();
|
||||||
mat.col(first).swap(mat.col(second));
|
mat.col(first).swap(mat.col(second));
|
||||||
m_T.rotate(mat);
|
m_T.rotate(mat);
|
||||||
|
this->UpdatePropertiesFromMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decomposes the internal matrix m_T back into Position, Orientation, and Scale properties.
|
||||||
|
*/
|
||||||
|
void UpdatePropertiesFromMatrix() {
|
||||||
|
// 1. Position
|
||||||
|
Transform.Position = m_T.translation();
|
||||||
|
|
||||||
|
// 2. Scale
|
||||||
|
Matrix3f linear = m_T.linear();
|
||||||
|
Transform.Scale(0) = linear.col(0).norm();
|
||||||
|
Transform.Scale(1) = linear.col(1).norm();
|
||||||
|
Transform.Scale(2) = linear.col(2).norm();
|
||||||
|
|
||||||
|
// 3. Rotation (Normalization removes scale)
|
||||||
|
Matrix3f rotation = linear;
|
||||||
|
if (Transform.Scale(0) > 1e-6) rotation.col(0) /= Transform.Scale(0);
|
||||||
|
if (Transform.Scale(1) > 1e-6) rotation.col(1) /= Transform.Scale(1);
|
||||||
|
if (Transform.Scale(2) > 1e-6) rotation.col(2) /= Transform.Scale(2);
|
||||||
|
|
||||||
|
// Euler YZY (indices 1, 2, 1)
|
||||||
|
Vector3f euler = rotation.eulerAngles(1, 2, 1);
|
||||||
|
Transform.Orientation = euler / CLHEP::degree;
|
||||||
|
|
||||||
|
// Notify properties
|
||||||
|
PropertyBase* p;
|
||||||
|
if ((p = this->GetProperty("Transform.Position"))) p->Updated();
|
||||||
|
if ((p = this->GetProperty("Transform.Orientation"))) p->Updated();
|
||||||
|
if ((p = this->GetProperty("Transform.Scale"))) p->Updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/** Signal emitted when properties change */
|
||||||
|
virtual void Updated() override {
|
||||||
|
this->Sync();
|
||||||
|
ULIB_SIGNAL_EMIT(AffineTransform::Updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Synchronizes m_T with properties */
|
||||||
|
void Sync() {
|
||||||
|
m_T = Eigen::Affine3f::Identity();
|
||||||
|
m_T.translate(Transform.Position);
|
||||||
|
|
||||||
|
// Orientation (using YZY order as implied by EulerYZYRotate)
|
||||||
|
Matrix3f mat;
|
||||||
|
mat = Eigen::AngleAxisf(Transform.Orientation.x() * CLHEP::degree, Vector3f::UnitY())
|
||||||
|
* Eigen::AngleAxisf(Transform.Orientation.y() * CLHEP::degree, Vector3f::UnitZ())
|
||||||
|
* Eigen::AngleAxisf(Transform.Orientation.z() * CLHEP::degree, Vector3f::UnitY());
|
||||||
|
m_T.rotate(mat);
|
||||||
|
|
||||||
|
m_T.scale(Transform.Scale);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,11 +37,12 @@
|
|||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
class TriangleMesh : public AffineTransform, public Object
|
class TriangleMesh : public AffineTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(TriangleMesh, AffineTransform)
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "TriangleMesh"; }
|
virtual const char * GetClassName() const override { return "TriangleMesh"; }
|
||||||
|
|
||||||
void PrintSelf(std::ostream &o);
|
void PrintSelf(std::ostream &o);
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <vtkVersion.h>
|
#include <vtkVersion.h>
|
||||||
#include "vtkViewport.h"
|
#include "vtkViewport.h"
|
||||||
#include "uLibVtkInterface.h"
|
#include "uLibVtkInterface.h"
|
||||||
|
#include "Math/Transform.h"
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
#include <vtkPolyDataMapper.h>
|
#include <vtkPolyDataMapper.h>
|
||||||
#include <vtkProperty.h>
|
#include <vtkProperty.h>
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
|
|
||||||
#include "uLibVtkInterface.h"
|
#include "uLibVtkInterface.h"
|
||||||
#include "vtkHandlerWidget.h"
|
#include "vtkHandlerWidget.h"
|
||||||
|
#include "Math/Dense.h"
|
||||||
#include "Core/Property.h"
|
#include "Core/Property.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -96,9 +98,9 @@ public:
|
|||||||
m_Dragable(true)
|
m_Dragable(true)
|
||||||
{
|
{
|
||||||
m_Color[0] = m_Color[1] = m_Color[2] = -1.0;
|
m_Color[0] = m_Color[1] = m_Color[2] = -1.0;
|
||||||
m_Position[0] = m_Position[1] = m_Position[2] = 0.0;
|
m_Position = Vector3d::Zero();
|
||||||
m_Orientation[0] = m_Orientation[1] = m_Orientation[2] = 0.0;
|
m_Orientation = Vector3d::Zero();
|
||||||
m_Scale[0] = m_Scale[1] = m_Scale[2] = 1.0;
|
m_Scale = Vector3d::Ones();
|
||||||
}
|
}
|
||||||
|
|
||||||
~PuppetData() {
|
~PuppetData() {
|
||||||
@@ -124,9 +126,9 @@ public:
|
|||||||
bool m_Selected;
|
bool m_Selected;
|
||||||
bool m_Visibility;
|
bool m_Visibility;
|
||||||
bool m_Dragable;
|
bool m_Dragable;
|
||||||
double m_Position[3];
|
Vector3d m_Position;
|
||||||
double m_Orientation[3];
|
Vector3d m_Orientation;
|
||||||
double m_Scale[3];
|
Vector3d m_Scale;
|
||||||
|
|
||||||
void ApplyAppearance(vtkProp *p) {
|
void ApplyAppearance(vtkProp *p) {
|
||||||
p->SetVisibility(m_Visibility);
|
p->SetVisibility(m_Visibility);
|
||||||
@@ -156,9 +158,9 @@ public:
|
|||||||
// Handle transformation if it's a Prop3D
|
// Handle transformation if it's a Prop3D
|
||||||
if (auto* p3d = vtkProp3D::SafeDownCast(p)) {
|
if (auto* p3d = vtkProp3D::SafeDownCast(p)) {
|
||||||
// NOTE: Usually managed by Puppet::Update from model, but here for direct prop manipulation
|
// NOTE: Usually managed by Puppet::Update from model, but here for direct prop manipulation
|
||||||
// p3d->SetPosition(m_Position);
|
// p3d->SetPosition(m_Position.data());
|
||||||
// p3d->SetOrientation(m_Orientation);
|
// p3d->SetOrientation(m_Orientation.data());
|
||||||
// p3d->SetScale(m_Scale);
|
// p3d->SetScale(m_Scale.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,7 +485,7 @@ void Puppet::SetSelected(bool selected)
|
|||||||
if (!pd->m_Selectable) return;
|
if (!pd->m_Selectable) return;
|
||||||
if (pd->m_Selected == selected) return;
|
if (pd->m_Selected == selected) return;
|
||||||
pd->m_Selected = selected;
|
pd->m_Selected = selected;
|
||||||
pd->UpdateHighlight();
|
pd->UpdateHighlight();0
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Puppet::IsSelected() const
|
bool Puppet::IsSelected() const
|
||||||
@@ -497,11 +499,28 @@ void Puppet::Update()
|
|||||||
if (root) {
|
if (root) {
|
||||||
pd->ApplyAppearance(root);
|
pd->ApplyAppearance(root);
|
||||||
|
|
||||||
// Apply transformation if it's a Prop3D
|
// Handle transformation synchronization from content
|
||||||
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
if (auto* content = dynamic_cast<uLib::AffineTransform*>(GetContent())) {
|
||||||
p3d->SetPosition(pd->m_Position);
|
pd->m_Position = content->GetPosition().cast<double>();
|
||||||
p3d->SetOrientation(pd->m_Orientation);
|
pd->m_Orientation = content->GetOrientation().cast<double>();
|
||||||
p3d->SetScale(pd->m_Scale);
|
pd->m_Scale = content->GetScale().cast<double>();
|
||||||
|
|
||||||
|
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||||
|
vtkNew<vtkMatrix4x4> vmat;
|
||||||
|
const Matrix4f& emat = content->GetMatrix();
|
||||||
|
for(int i=0; i<4; ++i) for(int j=0; j<4; ++j) vmat->SetElement(i, j, emat(i,j));
|
||||||
|
p3d->SetUserMatrix(vmat);
|
||||||
|
|
||||||
|
// Clear base transform to avoid double-application
|
||||||
|
p3d->SetPosition(0,0,0);
|
||||||
|
p3d->SetOrientation(0,0,0);
|
||||||
|
p3d->SetScale(1,1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||||
|
p3d->SetPosition(pd->m_Position.data());
|
||||||
|
p3d->SetOrientation(pd->m_Orientation.data());
|
||||||
|
p3d->SetScale(pd->m_Scale.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,23 +557,42 @@ void Puppet::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Puppet::SyncFromVtk()
|
void Puppet::SyncFromVtk()
|
||||||
{
|
{
|
||||||
vtkProp* root = this->GetProp();
|
vtkProp* root = this->GetProp();
|
||||||
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
|
||||||
double pos[3], ori[3], scale[3];
|
// Handle content synchronization if it's an AffineTransform
|
||||||
p3d->GetPosition(pos);
|
if (auto* content = dynamic_cast<uLib::AffineTransform*>(GetContent())) {
|
||||||
p3d->GetOrientation(ori);
|
vtkMatrix4x4* vmat = p3d->GetUserMatrix();
|
||||||
p3d->GetScale(scale);
|
if (vmat) {
|
||||||
|
Matrix4f emat;
|
||||||
// Update properties
|
for (int i=0; i<4; ++i)
|
||||||
for (int i=0; i<3; ++i) {
|
for (int j=0; j<4; ++j)
|
||||||
pd->m_Position[i] = pos[i];
|
emat(i, j) = vmat->GetElement(i, j);
|
||||||
pd->m_Orientation[i] = ori[i];
|
content->SetMatrix(emat);
|
||||||
pd->m_Scale[i] = scale[i];
|
|
||||||
|
// Re-sync internal puppet properties from the now-updated content
|
||||||
|
pd->m_Position = content->GetPosition().cast<double>();
|
||||||
|
pd->m_Orientation = content->GetOrientation().cast<double>();
|
||||||
|
pd->m_Scale = content->GetScale().cast<double>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Update internal puppet properties directly from base components
|
||||||
|
// only if no content exists (old behavior)
|
||||||
|
double pos[3], ori[3], scale[3];
|
||||||
|
p3d->GetPosition(pos);
|
||||||
|
p3d->GetOrientation(ori);
|
||||||
|
p3d->GetScale(scale);
|
||||||
|
for (int i=0; i<3; ++i) {
|
||||||
|
pd->m_Position(i) = pos[i];
|
||||||
|
pd->m_Orientation(i) = ori[i];
|
||||||
|
pd->m_Scale(i) = scale[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the properties from the object
|
// Notify puppet properties updated
|
||||||
if (auto* propPos = this->GetProperty("Position")) propPos->Updated();
|
if (auto* propPos = this->GetProperty("Position")) propPos->Updated();
|
||||||
if (auto* propOri = this->GetProperty("Orientation")) propOri->Updated();
|
if (auto* propOri = this->GetProperty("Orientation")) propOri->Updated();
|
||||||
if (auto* propScale = this->GetProperty("Scale")) propScale->Updated();
|
if (auto* propScale = this->GetProperty("Scale")) propScale->Updated();
|
||||||
@@ -567,26 +605,37 @@ void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TransformProxy {
|
||||||
|
PuppetData* pd;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int version) {
|
||||||
|
ar & boost::serialization::make_hrp("Position", pd->m_Position, "mm");
|
||||||
|
ar & boost::serialization::make_hrp("Orientation", pd->m_Orientation, "deg");
|
||||||
|
ar & boost::serialization::make_hrp("Scale", pd->m_Scale, "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AppearanceProxy {
|
||||||
|
PuppetData* pd;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int version) {
|
||||||
|
ar & boost::serialization::make_hrp("ColorR", pd->m_Color[0]);
|
||||||
|
ar & boost::serialization::make_hrp("ColorG", pd->m_Color[1]);
|
||||||
|
ar & boost::serialization::make_hrp("ColorB", pd->m_Color[2]);
|
||||||
|
ar & boost::serialization::make_hrp("Opacity", pd->m_Opacity);
|
||||||
|
ar & boost::serialization::make_hrp_enum("Representation", pd->m_Representation, {"Points", "Wireframe", "Surface", "SurfaceWithEdges", "Volume", "Outline", "Slice"});
|
||||||
|
ar & boost::serialization::make_hrp("Visibility", pd->m_Visibility);
|
||||||
|
ar & boost::serialization::make_hrp("Pickable", pd->m_Selectable);
|
||||||
|
ar & boost::serialization::make_hrp("Dragable", pd->m_Dragable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void Puppet::serialize_display(Archive::display_properties_archive & ar, const unsigned int version) {
|
void Puppet::serialize_display(Archive::display_properties_archive & ar, const unsigned int version) {
|
||||||
ar & boost::serialization::make_hrp("ColorR", pd->m_Color[0]);
|
AppearanceProxy appearance{pd};
|
||||||
ar & boost::serialization::make_hrp("ColorG", pd->m_Color[1]);
|
ar & boost::serialization::make_nvp("Appearance", appearance);
|
||||||
ar & boost::serialization::make_hrp("ColorB", pd->m_Color[2]);
|
|
||||||
ar & boost::serialization::make_hrp("Opacity", pd->m_Opacity);
|
|
||||||
ar & boost::serialization::make_hrp_enum("Representation", pd->m_Representation, {"Points", "Wireframe", "Surface", "SurfaceWithEdges", "Volume", "Outline", "Slice"});
|
|
||||||
ar & boost::serialization::make_hrp("Visibility", pd->m_Visibility);
|
|
||||||
ar & boost::serialization::make_hrp("Pickable", pd->m_Selectable);
|
|
||||||
ar & boost::serialization::make_hrp("Dragable", pd->m_Dragable);
|
|
||||||
|
|
||||||
// Geometry knobs (caution: these might be overridden by internal matrices)
|
TransformProxy transform{pd};
|
||||||
ar & boost::serialization::make_hrp("PosX", pd->m_Position[0], "mm");
|
ar & boost::serialization::make_nvp("Transform", transform);
|
||||||
ar & boost::serialization::make_hrp("PosY", pd->m_Position[1], "mm");
|
|
||||||
ar & boost::serialization::make_hrp("PosZ", pd->m_Position[2], "mm");
|
|
||||||
ar & boost::serialization::make_hrp("OriX", pd->m_Orientation[0], "deg");
|
|
||||||
ar & boost::serialization::make_hrp("OriY", pd->m_Orientation[1], "deg");
|
|
||||||
ar & boost::serialization::make_hrp("OriZ", pd->m_Orientation[2], "deg");
|
|
||||||
ar & boost::serialization::make_hrp("ScaleX", pd->m_Scale[0]);
|
|
||||||
ar & boost::serialization::make_hrp("ScaleY", pd->m_Scale[1]);
|
|
||||||
ar & boost::serialization::make_hrp("ScaleZ", pd->m_Scale[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Puppet::serialize(Archive::xml_oarchive & ar, const unsigned int v) { }
|
void Puppet::serialize(Archive::xml_oarchive & ar, const unsigned int v) { }
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <boost/type_traits/is_class.hpp>
|
||||||
|
#include <boost/mpl/bool.hpp>
|
||||||
|
#include <boost/serialization/serialization.hpp>
|
||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
#include "Core/Property.h"
|
#include "Core/Property.h"
|
||||||
#include "Core/Monitor.h"
|
#include "Core/Monitor.h"
|
||||||
@@ -157,10 +160,19 @@ public:
|
|||||||
boost::archive::detail::common_oarchive<display_properties_archive>(boost::archive::no_header),
|
boost::archive::detail::common_oarchive<display_properties_archive>(boost::archive::no_header),
|
||||||
m_Puppet(puppet) {}
|
m_Puppet(puppet) {}
|
||||||
|
|
||||||
|
std::string GetCurrentGroup() const {
|
||||||
|
std::string group;
|
||||||
|
for (const auto& g : m_GroupStack) {
|
||||||
|
if (!group.empty()) group += ".";
|
||||||
|
group += g;
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void save_override(const boost::serialization::hrp<T> &t) {
|
void save_override(const boost::serialization::hrp<T> &t) {
|
||||||
if (m_Puppet) {
|
if (m_Puppet) {
|
||||||
uLib::Property<T>* p = new uLib::Property<T>(m_Puppet, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "");
|
uLib::Property<T>* p = new uLib::Property<T>(m_Puppet, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
m_Puppet->RegisterDisplayProperty(p);
|
m_Puppet->RegisterDisplayProperty(p);
|
||||||
Vtk::Puppet* puppet = m_Puppet;
|
Vtk::Puppet* puppet = m_Puppet;
|
||||||
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
|
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
|
||||||
@@ -170,7 +182,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
void save_override(const boost::serialization::hrp_enum<T> &t) {
|
void save_override(const boost::serialization::hrp_enum<T> &t) {
|
||||||
if (m_Puppet) {
|
if (m_Puppet) {
|
||||||
uLib::EnumProperty* p = new uLib::EnumProperty(m_Puppet, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "");
|
uLib::EnumProperty* p = new uLib::EnumProperty(m_Puppet, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
m_Puppet->RegisterDisplayProperty(p);
|
m_Puppet->RegisterDisplayProperty(p);
|
||||||
Vtk::Puppet* puppet = m_Puppet;
|
Vtk::Puppet* puppet = m_Puppet;
|
||||||
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
|
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
|
||||||
@@ -178,10 +190,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T> void save_override(const boost::serialization::nvp<T> &t) {
|
template<class T> void save_override(const boost::serialization::nvp<T> &t) {
|
||||||
boost::archive::detail::common_oarchive<display_properties_archive>::save_override(t.const_value());
|
if (t.name()) m_GroupStack.push_back(t.name());
|
||||||
|
this->save_helper(t.const_value(), typename boost::is_class<T>::type());
|
||||||
|
if (t.name()) m_GroupStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> void save_override(const T &t) {}
|
// Recursion for nested classes, ignore primitives
|
||||||
|
template<class T> void save_override(const T &t) {
|
||||||
|
this->save_helper(t, typename boost::is_class<T>::type());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::true_) {
|
||||||
|
boost::serialization::serialize_adl(*this, const_cast<T&>(t), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::false_) {}
|
||||||
|
|
||||||
void save_override(const boost::archive::object_id_type & t) {}
|
void save_override(const boost::archive::object_id_type & t) {}
|
||||||
void save_override(const boost::archive::object_reference_type & t) {}
|
void save_override(const boost::archive::object_reference_type & t) {}
|
||||||
@@ -194,6 +219,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Vtk::Puppet* m_Puppet;
|
Vtk::Puppet* m_Puppet;
|
||||||
|
std::vector<std::string> m_GroupStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Archive
|
} // namespace Archive
|
||||||
|
|||||||
@@ -110,17 +110,16 @@ void vtkObjectsContext::Update() {
|
|||||||
Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
|
Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
|
||||||
if (!obj) return nullptr;
|
if (!obj) return nullptr;
|
||||||
|
|
||||||
const char* className = obj->GetClassName();
|
if (auto* box = dynamic_cast<uLib::ContainerBox*>(obj)) {
|
||||||
if (std::strcmp(className, "ContainerBox") == 0) {
|
return new vtkContainerBox(box);
|
||||||
return new vtkContainerBox(static_cast<uLib::ContainerBox*>(obj));
|
} else if (auto* chamber = dynamic_cast<uLib::DetectorChamber*>(obj)) {
|
||||||
} else if (std::strcmp(className, "DetectorChamber") == 0) {
|
return new vtkDetectorChamber(chamber);
|
||||||
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
|
} else if (auto* cylinder = dynamic_cast<uLib::Cylinder*>(obj)) {
|
||||||
} else if (std::strcmp(className, "Cylinder") == 0) {
|
return new vtkCylinder(cylinder);
|
||||||
return new vtkCylinder(static_cast<uLib::Cylinder*>(obj));
|
} else if (auto* vox = dynamic_cast<uLib::Abstract::VoxImage*>(obj)) {
|
||||||
} else if (std::strcmp(className, "VoxImage") == 0) {
|
return new vtkVoxImage(*vox);
|
||||||
return new vtkVoxImage(*static_cast<uLib::Abstract::VoxImage*>(obj));
|
} else if (auto* assembly = dynamic_cast<uLib::Assembly*>(obj)) {
|
||||||
} else if (std::strcmp(className, "Assembly") == 0) {
|
return new Assembly(assembly);
|
||||||
return new Assembly(static_cast<uLib::Assembly*>(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback if we don't know the exact class but it might be a context itself
|
// Fallback if we don't know the exact class but it might be a context itself
|
||||||
|
|||||||
Reference in New Issue
Block a user