add cylinder
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
#include "PropertyWidgets.h"
|
#include "PropertyWidgets.h"
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QRegularExpressionMatch>
|
||||||
#include "Vtk/uLibVtkInterface.h"
|
#include "Vtk/uLibVtkInterface.h"
|
||||||
|
#include "Math/Units.h"
|
||||||
|
#include "Math/Dense.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Qt {
|
namespace Qt {
|
||||||
@@ -15,57 +19,124 @@ PropertyWidgetBase::PropertyWidgetBase(PropertyBase* prop, QWidget* parent)
|
|||||||
}
|
}
|
||||||
PropertyWidgetBase::~PropertyWidgetBase() {}
|
PropertyWidgetBase::~PropertyWidgetBase() {}
|
||||||
|
|
||||||
|
// Helper for unit parsing
|
||||||
|
static double parseWithUnits(const QString& text, double* factorOut = nullptr, QString* suffixOut = nullptr) {
|
||||||
|
static QRegularExpression re("^\\s*([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s*(_?[a-zA-Z]+)?\\s*$");
|
||||||
|
QRegularExpressionMatch match = re.match(text);
|
||||||
|
if (!match.hasMatch()) return 0.0;
|
||||||
|
|
||||||
|
double num = match.captured(1).toDouble();
|
||||||
|
QString unit = match.captured(3);
|
||||||
|
double factor = 1.0;
|
||||||
|
|
||||||
|
if (!unit.isEmpty()) {
|
||||||
|
QString u = unit.startsWith('_') ? unit.mid(1) : unit;
|
||||||
|
if (u == "m") factor = CLHEP::meter;
|
||||||
|
else if (u == "cm") factor = CLHEP::centimeter;
|
||||||
|
else if (u == "mm") factor = CLHEP::millimeter;
|
||||||
|
else if (u == "um") factor = CLHEP::micrometer;
|
||||||
|
else if (u == "nm") factor = CLHEP::nanometer;
|
||||||
|
else if (u == "km") factor = CLHEP::kilometer;
|
||||||
|
else if (u == "deg") factor = CLHEP::degree;
|
||||||
|
else if (u == "rad") factor = CLHEP::radian;
|
||||||
|
else if (u == "ns") factor = CLHEP::nanosecond;
|
||||||
|
else if (u == "s") factor = CLHEP::second;
|
||||||
|
else if (u == "ms") factor = CLHEP::millisecond;
|
||||||
|
else if (u == "MeV") factor = CLHEP::megaelectronvolt;
|
||||||
|
else if (u == "eV") factor = CLHEP::electronvolt;
|
||||||
|
else if (u == "keV") factor = CLHEP::kiloelectronvolt;
|
||||||
|
else if (u == "GeV") factor = CLHEP::gigaelectronvolt;
|
||||||
|
else if (u == "TeV") factor = CLHEP::teraelectronvolt;
|
||||||
|
if (suffixOut) *suffixOut = u;
|
||||||
|
} else if (suffixOut) {
|
||||||
|
// Reuse previous suffix if none provided, or empty
|
||||||
|
}
|
||||||
|
|
||||||
|
if (factorOut) *factorOut = factor;
|
||||||
|
return num * factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitLineEdit implementation
|
||||||
|
UnitLineEdit::UnitLineEdit(QWidget* parent) : QLineEdit(parent), m_Value(0), m_Factor(1.0), m_Suffix("mm"), m_IsInteger(false) {
|
||||||
|
connect(this, &QLineEdit::editingFinished, this, &UnitLineEdit::onEditingFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitLineEdit::setValue(double val) {
|
||||||
|
if (m_Value != val) {
|
||||||
|
m_Value = val;
|
||||||
|
// Initial heuristic for unit if it was mm and value becomes large
|
||||||
|
if (!m_IsInteger && m_Suffix == "mm" && std::abs(val) >= 1000.0) { m_Suffix = "m"; m_Factor = CLHEP::meter; }
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitLineEdit::onEditingFinished() {
|
||||||
|
double factor = m_Factor;
|
||||||
|
QString suffix = m_Suffix;
|
||||||
|
double parsedVal = parseWithUnits(text(), &factor, &suffix);
|
||||||
|
if (!suffix.isEmpty()) {
|
||||||
|
m_Suffix = suffix;
|
||||||
|
m_Factor = factor;
|
||||||
|
}
|
||||||
|
if (m_IsInteger) {
|
||||||
|
parsedVal = std::round(parsedVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Value != parsedVal) {
|
||||||
|
m_Value = parsedVal;
|
||||||
|
emit valueManualChanged(m_Value);
|
||||||
|
}
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitLineEdit::updateText() {
|
||||||
|
QSignalBlocker blocker(this);
|
||||||
|
if (m_IsInteger) {
|
||||||
|
setText(QString::number((int)m_Value));
|
||||||
|
} else {
|
||||||
|
double displayVal = m_Value / m_Factor;
|
||||||
|
setText(QString::number(displayVal, 'g', 6) + " " + m_Suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitLineEdit::setIntegerOnly(bool integerOnly) {
|
||||||
|
m_IsInteger = integerOnly;
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
|
||||||
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_SpinBox = new QDoubleSpinBox(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
m_SpinBox->setRange(-1000000.0, 1000000.0);
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
m_SpinBox->setValue(prop->Get());
|
m_Edit->setValue(prop->Get());
|
||||||
m_Layout->addWidget(m_SpinBox, 1);
|
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set(val); });
|
||||||
connect(m_SpinBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
|
||||||
[this](double val){ if (m_Prop->Get() != val) m_Prop->Set(val); });
|
|
||||||
uLib::Object::connect(m_Prop, &Property<double>::PropertyChanged, [this](){
|
uLib::Object::connect(m_Prop, &Property<double>::PropertyChanged, [this](){
|
||||||
if (m_SpinBox->value() != m_Prop->Get()) {
|
m_Edit->setValue(m_Prop->Get());
|
||||||
QSignalBlocker blocker(m_SpinBox);
|
|
||||||
m_SpinBox->setValue(m_Prop->Get());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
DoublePropertyWidget::~DoublePropertyWidget() {}
|
|
||||||
|
|
||||||
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_SpinBox = new QDoubleSpinBox(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
m_SpinBox->setRange(-1000000.0, 1000000.0);
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
m_SpinBox->setDecimals(3);
|
m_Edit->setValue(prop->Get());
|
||||||
m_SpinBox->setValue(prop->Get());
|
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((float)val); });
|
||||||
m_Layout->addWidget(m_SpinBox, 1);
|
|
||||||
connect(m_SpinBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
|
||||||
[this](double val){ if (m_Prop->Get() != (float)val) m_Prop->Set((float)val); });
|
|
||||||
uLib::Object::connect(m_Prop, &Property<float>::PropertyChanged, [this](){
|
uLib::Object::connect(m_Prop, &Property<float>::PropertyChanged, [this](){
|
||||||
if (m_SpinBox->value() != (double)m_Prop->Get()) {
|
m_Edit->setValue((double)m_Prop->Get());
|
||||||
QSignalBlocker blocker(m_SpinBox);
|
|
||||||
m_SpinBox->setValue((double)m_Prop->Get());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
FloatPropertyWidget::~FloatPropertyWidget() {}
|
|
||||||
|
|
||||||
IntPropertyWidget::IntPropertyWidget(Property<int>* prop, QWidget* parent)
|
IntPropertyWidget::IntPropertyWidget(Property<int>* prop, QWidget* parent)
|
||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
m_SpinBox = new QSpinBox(this);
|
m_Edit = new UnitLineEdit(this);
|
||||||
m_SpinBox->setRange(-1000000, 1000000);
|
m_Edit->setIntegerOnly(true);
|
||||||
m_SpinBox->setValue(prop->Get());
|
m_Layout->addWidget(m_Edit, 1);
|
||||||
m_Layout->addWidget(m_SpinBox, 1);
|
m_Edit->setValue(prop->Get());
|
||||||
connect(m_SpinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((int)val); });
|
||||||
[this](int val){ if (m_Prop->Get() != val) m_Prop->Set(val); });
|
|
||||||
uLib::Object::connect(m_Prop, &Property<int>::PropertyChanged, [this](){
|
uLib::Object::connect(m_Prop, &Property<int>::PropertyChanged, [this](){
|
||||||
if (m_SpinBox->value() != m_Prop->Get()) {
|
m_Edit->setValue((double)m_Prop->Get());
|
||||||
QSignalBlocker blocker(m_SpinBox);
|
|
||||||
m_SpinBox->setValue(m_Prop->Get());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IntPropertyWidget::~IntPropertyWidget() {}
|
|
||||||
|
|
||||||
BoolPropertyWidget::BoolPropertyWidget(Property<bool>* prop, QWidget* parent)
|
BoolPropertyWidget::BoolPropertyWidget(Property<bool>* prop, QWidget* parent)
|
||||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
@@ -126,6 +197,17 @@ PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent), m_Object(null
|
|||||||
registerFactory<std::string>([](PropertyBase* p, QWidget* parent){
|
registerFactory<std::string>([](PropertyBase* p, QWidget* parent){
|
||||||
return new StringPropertyWidget(static_cast<Property<std::string>*>(p), parent);
|
return new StringPropertyWidget(static_cast<Property<std::string>*>(p), parent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Vector Registration
|
||||||
|
registerFactory<Vector2i>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector2i, 2>(static_cast<Property<Vector2i>*>(p), parent); });
|
||||||
|
registerFactory<Vector2f>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector2f, 2>(static_cast<Property<Vector2f>*>(p), parent); });
|
||||||
|
registerFactory<Vector2d>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector2d, 2>(static_cast<Property<Vector2d>*>(p), parent); });
|
||||||
|
registerFactory<Vector3i>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector3i, 3>(static_cast<Property<Vector3i>*>(p), parent); });
|
||||||
|
registerFactory<Vector3f>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector3f, 3>(static_cast<Property<Vector3f>*>(p), parent); });
|
||||||
|
registerFactory<Vector3d>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector3d, 3>(static_cast<Property<Vector3d>*>(p), parent); });
|
||||||
|
registerFactory<Vector4i>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector4i, 4>(static_cast<Property<Vector4i>*>(p), parent); });
|
||||||
|
registerFactory<Vector4f>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector4f, 4>(static_cast<Property<Vector4f>*>(p), parent); });
|
||||||
|
registerFactory<Vector4d>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector4d, 4>(static_cast<Property<Vector4d>*>(p), parent); });
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyEditor::~PropertyEditor() {}
|
PropertyEditor::~PropertyEditor() {}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QDoubleSpinBox>
|
|
||||||
#include <QSpinBox>
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
@@ -16,6 +14,7 @@
|
|||||||
|
|
||||||
#include "Core/Property.h"
|
#include "Core/Property.h"
|
||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
|
#include "Math/Dense.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Qt {
|
namespace Qt {
|
||||||
@@ -33,34 +32,90 @@ protected:
|
|||||||
QLabel* m_Label;
|
QLabel* m_Label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UnitLineEdit : public QLineEdit {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
UnitLineEdit(QWidget* parent = nullptr);
|
||||||
|
void setValue(double val);
|
||||||
|
double getValue() const { return m_Value; }
|
||||||
|
void setIntegerOnly(bool b);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void valueManualChanged(double val);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onEditingFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateText();
|
||||||
|
double m_Value;
|
||||||
|
double m_Factor;
|
||||||
|
QString m_Suffix;
|
||||||
|
bool m_IsInteger;
|
||||||
|
};
|
||||||
|
|
||||||
class DoublePropertyWidget : public PropertyWidgetBase {
|
class DoublePropertyWidget : public PropertyWidgetBase {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DoublePropertyWidget(Property<double>* prop, QWidget* parent = nullptr);
|
DoublePropertyWidget(Property<double>* prop, QWidget* parent = nullptr);
|
||||||
virtual ~DoublePropertyWidget();
|
|
||||||
private:
|
private:
|
||||||
Property<double>* m_Prop;
|
Property<double>* m_Prop;
|
||||||
QDoubleSpinBox* m_SpinBox;
|
UnitLineEdit* m_Edit;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FloatPropertyWidget : public PropertyWidgetBase {
|
class FloatPropertyWidget : public PropertyWidgetBase {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FloatPropertyWidget(Property<float>* prop, QWidget* parent = nullptr);
|
FloatPropertyWidget(Property<float>* prop, QWidget* parent = nullptr);
|
||||||
virtual ~FloatPropertyWidget();
|
|
||||||
private:
|
private:
|
||||||
Property<float>* m_Prop;
|
Property<float>* m_Prop;
|
||||||
QDoubleSpinBox* m_SpinBox;
|
UnitLineEdit* m_Edit;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IntPropertyWidget : public PropertyWidgetBase {
|
class IntPropertyWidget : public PropertyWidgetBase {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
IntPropertyWidget(Property<int>* prop, QWidget* parent = nullptr);
|
IntPropertyWidget(Property<int>* prop, QWidget* parent = nullptr);
|
||||||
virtual ~IntPropertyWidget();
|
|
||||||
private:
|
private:
|
||||||
Property<int>* m_Prop;
|
Property<int>* m_Prop;
|
||||||
QSpinBox* m_SpinBox;
|
UnitLineEdit* m_Edit;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename VecT, int Size>
|
||||||
|
class VectorPropertyWidget : public PropertyWidgetBase {
|
||||||
|
public:
|
||||||
|
VectorPropertyWidget(Property<VecT>* prop, QWidget* parent = nullptr)
|
||||||
|
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||||
|
for (int i = 0; i < Size; ++i) {
|
||||||
|
m_Edits[i] = new UnitLineEdit(this);
|
||||||
|
if (std::is_integral<typename VecT::Scalar>::value) {
|
||||||
|
m_Edits[i]->setIntegerOnly(true);
|
||||||
|
}
|
||||||
|
m_Layout->addWidget(m_Edits[i], 1);
|
||||||
|
|
||||||
|
connect(m_Edits[i], &UnitLineEdit::valueManualChanged, [this, i](double val){
|
||||||
|
VecT v = m_Prop->Get();
|
||||||
|
v(i) = (typename VecT::Scalar)val;
|
||||||
|
if (m_Prop->Get() != v) m_Prop->Set(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateEdits();
|
||||||
|
uLib::Object::connect(m_Prop, &Property<VecT>::PropertyChanged, [this](){
|
||||||
|
updateEdits();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateEdits() {
|
||||||
|
VecT v = m_Prop->Get();
|
||||||
|
for (int i = 0; i < Size; ++i) {
|
||||||
|
if (!m_Edits[i]->hasFocus()) {
|
||||||
|
m_Edits[i]->setValue((double)v(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Property<VecT>* m_Prop;
|
||||||
|
UnitLineEdit* m_Edits[Size];
|
||||||
};
|
};
|
||||||
|
|
||||||
class BoolPropertyWidget : public PropertyWidgetBase {
|
class BoolPropertyWidget : public PropertyWidgetBase {
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ void Object::RegisterProperty(PropertyBase* prop) {
|
|||||||
void Object::RegisterDynamicProperty(PropertyBase* prop) {
|
void Object::RegisterDynamicProperty(PropertyBase* prop) {
|
||||||
if (prop) {
|
if (prop) {
|
||||||
d->m_DynamicProperties.push_back(prop);
|
d->m_DynamicProperties.push_back(prop);
|
||||||
d->m_Properties.push_back(prop);
|
// Note: prop already added itself to m_Properties
|
||||||
|
// during its own constructor call to owner->RegisterProperty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +115,9 @@ template void Object::serialize(Archive::log_archive &, const unsigned int);
|
|||||||
// OBJECT IMPLEMENTATION
|
// OBJECT IMPLEMENTATION
|
||||||
|
|
||||||
Object::Object() : d(new ObjectPrivate) {}
|
Object::Object() : d(new ObjectPrivate) {}
|
||||||
|
Object::Object(const Object ©) : d(new ObjectPrivate) {
|
||||||
Object::Object(const Object ©) : d(new ObjectPrivate(*copy.d)) {}
|
if (copy.d) d->m_InstanceName = copy.d->m_InstanceName;
|
||||||
|
}
|
||||||
|
|
||||||
Object::~Object() {
|
Object::~Object() {
|
||||||
for (auto* p : d->m_DynamicProperties) {
|
for (auto* p : d->m_DynamicProperties) {
|
||||||
@@ -125,9 +127,11 @@ Object::~Object() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Object::DeepCopy(const Object ©) {
|
void Object::DeepCopy(const Object ©) {
|
||||||
// should lock to be tread safe //
|
if (this == ©) return;
|
||||||
memcpy(d, copy.d, sizeof(ObjectPrivate));
|
if (copy.d) d->m_InstanceName = copy.d->m_InstanceName;
|
||||||
// ERROR! does not copy parameters ... <<<< FIXXXXX
|
// Note: signals, slots and properties are intentionally not copied
|
||||||
|
// to maintain instance uniquely and avoid duplicate registrations.
|
||||||
|
this->Updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::SaveXml(std::ostream &os, Object &ob) {
|
void Object::SaveXml(std::ostream &os, Object &ob) {
|
||||||
|
|||||||
@@ -126,6 +126,12 @@ private:
|
|||||||
G4Box *m_Solid;
|
G4Box *m_Solid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Geant
|
} // namespace Geant
|
||||||
} // namespace uLib
|
} // namespace uLib
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
set(HEADERS ContainerBox.h
|
set(HEADERS ContainerBox.h
|
||||||
|
Cylinder.h
|
||||||
Dense.h
|
Dense.h
|
||||||
Geometry.h
|
Geometry.h
|
||||||
Transform.h
|
Transform.h
|
||||||
@@ -70,4 +71,3 @@ if(BUILD_TESTING)
|
|||||||
include(uLibTargetMacros)
|
include(uLibTargetMacros)
|
||||||
add_subdirectory(testing)
|
add_subdirectory(testing)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,8 @@ class ContainerBox : public AffineTransform, public Object {
|
|||||||
public:
|
public:
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// PROPERTIES //
|
// PROPERTIES //
|
||||||
Property<float> Width;
|
Property<Vector3f> p_Size;
|
||||||
Property<float> Height;
|
Property<Vector3f> p_Origin;
|
||||||
Property<float> Depth;
|
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "ContainerBox"; }
|
virtual const char * GetClassName() const { return "ContainerBox"; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,12 +61,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
ContainerBox()
|
ContainerBox()
|
||||||
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
||||||
Width(this, "Width", 1.0f),
|
p_Size(this, "Size", Vector3f(1.0f, 1.0f, 1.0f)),
|
||||||
Height(this, "Height", 1.0f),
|
p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) {
|
||||||
Depth(this, "Depth", 1.0f) {
|
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
||||||
Object::connect(&Width, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
||||||
Object::connect(&Height, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
|
||||||
Object::connect(&Depth, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,12 +73,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
ContainerBox(const Vector3f &size)
|
ContainerBox(const Vector3f &size)
|
||||||
: m_LocalT(this),
|
: m_LocalT(this),
|
||||||
Width(this, "Width", size(0)),
|
p_Size(this, "Size", size),
|
||||||
Height(this, "Height", size(1)),
|
p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) {
|
||||||
Depth(this, "Depth", size(2)) {
|
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
||||||
Object::connect(&Width, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
||||||
Object::connect(&Height, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
this->SetSize(size);
|
||||||
Object::connect(&Depth, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,20 +87,20 @@ public:
|
|||||||
ContainerBox(const ContainerBox ©)
|
ContainerBox(const ContainerBox ©)
|
||||||
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
||||||
AffineTransform(copy),
|
AffineTransform(copy),
|
||||||
Width(this, "Width", copy.Width),
|
p_Size(this, "Size", copy.p_Size),
|
||||||
Height(this, "Height", copy.Height),
|
p_Origin(this, "Origin", copy.p_Origin) {
|
||||||
Depth(this, "Depth", copy.Depth) {
|
Object::connect(&p_Size, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncSize);
|
||||||
Object::connect(&Width, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
Object::connect(&p_Origin, &Property<Vector3f>::PropertyChanged, this, &ContainerBox::SyncOrigin);
|
||||||
Object::connect(&Height, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
|
||||||
Object::connect(&Depth, &Property<float>::PropertyChanged, this, &ContainerBox::SyncSize);
|
|
||||||
this->SetOrigin(copy.GetOrigin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the box origin relative to its coordinate system.
|
* @brief Sets the box origin relative to its coordinate system.
|
||||||
* @param v The origin position vector.
|
* @param v The origin position vector.
|
||||||
*/
|
*/
|
||||||
void SetOrigin(const Vector3f &v) { m_LocalT.SetPosition(v); }
|
void SetOrigin(const Vector3f &v) {
|
||||||
|
p_Origin = v;
|
||||||
|
m_LocalT.SetPosition(v);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the box origin relative to its coordinate system.
|
* @brief Gets the box origin relative to its coordinate system.
|
||||||
@@ -119,9 +114,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) {
|
||||||
Width = v(0);
|
p_Size = v;
|
||||||
Height = v(1);
|
|
||||||
Depth = v(2);
|
|
||||||
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);
|
||||||
@@ -213,11 +206,17 @@ signals:
|
|||||||
// signal to emit when the box is updated //
|
// signal to emit when the box is updated //
|
||||||
virtual void Updated() override { ULIB_SIGNAL_EMIT(ContainerBox::Updated); }
|
virtual void Updated() override { ULIB_SIGNAL_EMIT(ContainerBox::Updated); }
|
||||||
|
|
||||||
private:
|
private slots:
|
||||||
void SyncSize() {
|
void SyncSize() {
|
||||||
this->SetSize(Vector3f(Width, Height, Depth));
|
this->SetSize(p_Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncOrigin() {
|
||||||
|
this->SetOrigin(p_Origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
AffineTransform m_LocalT;
|
AffineTransform m_LocalT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,32 +34,32 @@
|
|||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents a cylindrical volume centered in the base circle.
|
* @brief Represents a cylindrical volume.
|
||||||
*
|
*
|
||||||
* Cylinder inherits from AffineTransform, which defines its parent
|
* The cylinder orientation is defined by the Axis property (0=X, 1=Y, 2=Z).
|
||||||
* coordinate system. It contains an internal local transformation (m_LocalT)
|
* By default, it is aligned with the Y axis (Axis=1).
|
||||||
* that defines the cylinder's actual volume (radius and height)
|
|
||||||
* relative to the emitter's origin (base circle center).
|
|
||||||
*/
|
*/
|
||||||
class Cylinder : public AffineTransform, public Object {
|
class Cylinder : public AffineTransform, public Object {
|
||||||
typedef AffineTransform BaseClass;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
uLibTypeMacro(Cylinder, Object)
|
||||||
|
|
||||||
virtual const char * GetClassName() const { return "Cylinder"; }
|
virtual const char * GetClassName() const override { return "Cylinder"; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor.
|
* @brief Default constructor. Aligns with Y by default.
|
||||||
* Initializes with radius 1 and height 1.
|
|
||||||
*/
|
*/
|
||||||
Cylinder() : m_LocalT(this), m_Radius(1.0), m_Height(1.0) {
|
Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) {
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
UpdateLocalMatrix();
|
UpdateLocalMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor with radius and height.
|
* @brief Constructor with radius and height.
|
||||||
*/
|
*/
|
||||||
Cylinder(float radius, float height) : m_LocalT(this), m_Radius(radius), m_Height(height) {
|
Cylinder(float radius, float height, int axis = 1)
|
||||||
|
: m_LocalT(this), Radius(radius), Height(height), Axis(axis) {
|
||||||
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
UpdateLocalMatrix();
|
UpdateLocalMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,75 +67,115 @@ public:
|
|||||||
* @brief Copy constructor.
|
* @brief Copy constructor.
|
||||||
*/
|
*/
|
||||||
Cylinder(const Cylinder ©)
|
Cylinder(const Cylinder ©)
|
||||||
: m_LocalT(this), AffineTransform(copy) {
|
: m_LocalT(this), AffineTransform(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) {
|
||||||
this->SetRadius(copy.GetRadius());
|
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||||
this->SetHeight(copy.GetHeight());
|
this->UpdateLocalMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serialization template for property registration and persistence.
|
||||||
|
*/
|
||||||
|
template <class ArchiveT>
|
||||||
|
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||||
|
ar & HRP(Radius);
|
||||||
|
ar & HRP(Height);
|
||||||
|
ar & HRP(Axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the radius of the cylinder */
|
/** Sets the radius of the cylinder */
|
||||||
inline void SetRadius(float r) {
|
inline void SetRadius(float r) {
|
||||||
m_Radius = r;
|
Radius = r;
|
||||||
UpdateLocalMatrix();
|
UpdateLocalMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the radius of the cylinder */
|
/** Gets the radius of the cylinder */
|
||||||
inline float GetRadius() const { return m_Radius; }
|
inline float GetRadius() const { return Radius; }
|
||||||
|
|
||||||
/** Sets the height of the cylinder */
|
/** Sets the height of the cylinder */
|
||||||
inline void SetHeight(float h) {
|
inline void SetHeight(float h) {
|
||||||
m_Height = h;
|
Height = h;
|
||||||
UpdateLocalMatrix();
|
UpdateLocalMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the height of the cylinder */
|
/** Gets the height of the cylinder */
|
||||||
inline float GetHeight() const { return m_Height; }
|
inline float GetHeight() const { return Height; }
|
||||||
|
|
||||||
|
/** Sets the main axis (0=X, 1=Y, 2=Z) */
|
||||||
|
inline void SetAxis(int axis) {
|
||||||
|
Axis = axis;
|
||||||
|
UpdateLocalMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the main axis */
|
||||||
|
inline int GetAxis() const { return Axis; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the world transformation matrix of the cylinder's volume.
|
* @brief Returns the world transformation matrix.
|
||||||
*/
|
*/
|
||||||
Matrix4f GetWorldMatrix() const { return m_LocalT.GetWorldMatrix(); }
|
Matrix4f GetWorldMatrix() const { return m_LocalT.GetWorldMatrix(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the local transformation matrix of the cylinder's volume.
|
* @brief Returns the local transformation matrix.
|
||||||
*/
|
*/
|
||||||
Matrix4f GetLocalMatrix() const { return m_LocalT.GetMatrix(); }
|
Matrix4f GetLocalMatrix() const { return m_LocalT.GetMatrix(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Transforms local cylindrical coordinates to world space.
|
* @brief Transforms local cylindrical coordinates to world space.
|
||||||
* @param r Local radius (absolute).
|
* @param r Local radius.
|
||||||
* @param theta Local angle in radians.
|
* @param theta Local angle in radians (around main axis).
|
||||||
* @param z Local height (absolute, relative to base circle).
|
* @param h Local height along main axis.
|
||||||
* @return Transformed point in world space.
|
|
||||||
*/
|
*/
|
||||||
inline Vector4f GetWorldPoint(float r, float theta, float z) const {
|
inline Vector4f GetWorldPoint(float r, float theta, float h) const {
|
||||||
return BaseClass::GetWorldMatrix() * Vector4f(r * std::cos(theta), r * std::sin(theta), z, 1.0f);
|
Vector3f p;
|
||||||
|
if (Axis == 0) p = Vector3f(h, r * std::cos(theta), r * std::sin(theta));
|
||||||
|
else if (Axis == 1) p = Vector3f(r * std::cos(theta), h, r * std::sin(theta));
|
||||||
|
else p = Vector3f(r * std::cos(theta), r * std::sin(theta), h);
|
||||||
|
|
||||||
|
return AffineTransform::GetWorldMatrix() * Vector4f(p.x(), p.y(), p.z(), 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Transforms a world point to cylindrical local space.
|
* @brief Transforms a world point to cylindrical local space.
|
||||||
* @return Vector3f(r, theta, z)
|
* @return Vector3f(r, theta, h)
|
||||||
*/
|
*/
|
||||||
inline Vector3f GetCylindricalLocal(const Vector4f &world_v) const {
|
inline Vector3f GetCylindricalLocal(const Vector4f &world_v) const {
|
||||||
Vector4f local_v = BaseClass::GetWorldMatrix().inverse() * world_v;
|
Vector4f local_v = AffineTransform::GetWorldMatrix().inverse() * world_v;
|
||||||
float r = std::sqrt(local_v.x() * local_v.x() + local_v.y() * local_v.y());
|
float r, theta, h;
|
||||||
float theta = std::atan2(local_v.y(), local_v.x());
|
if (Axis == 0) {
|
||||||
return Vector3f(r, theta, local_v.z());
|
h = local_v.x();
|
||||||
|
r = std::sqrt(local_v.y() * local_v.y() + local_v.z() * local_v.z());
|
||||||
|
theta = std::atan2(local_v.z(), local_v.y());
|
||||||
|
} else if (Axis == 1) {
|
||||||
|
h = local_v.y();
|
||||||
|
r = std::sqrt(local_v.x() * local_v.x() + local_v.z() * local_v.z());
|
||||||
|
theta = std::atan2(local_v.z(), local_v.x());
|
||||||
|
} else {
|
||||||
|
h = local_v.z();
|
||||||
|
r = std::sqrt(local_v.x() * local_v.x() + local_v.y() * local_v.y());
|
||||||
|
theta = std::atan2(local_v.y(), local_v.x());
|
||||||
|
}
|
||||||
|
return Vector3f(r, theta, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/** Signal emitted when the cylinder geometry or transform is updated */
|
/** Signal emitted when properties change */
|
||||||
virtual void Updated() override { ULIB_SIGNAL_EMIT(Cylinder::Updated); }
|
virtual void Updated() override {
|
||||||
|
this->UpdateLocalMatrix();
|
||||||
private:
|
ULIB_SIGNAL_EMIT(Cylinder::Updated);
|
||||||
/** Recalculates the internal local matrix based on radius and height */
|
|
||||||
void UpdateLocalMatrix() {
|
|
||||||
m_LocalT = AffineTransform(this); // BaseClass is parent
|
|
||||||
m_LocalT.Scale(Vector3f(m_Radius, m_Radius, m_Height));
|
|
||||||
this->Updated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float m_Radius;
|
private:
|
||||||
float m_Height;
|
/** Recalculates the internal local matrix based on dimensions and axis */
|
||||||
|
void UpdateLocalMatrix() {
|
||||||
|
m_LocalT = AffineTransform(this);
|
||||||
|
if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius));
|
||||||
|
else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius));
|
||||||
|
else m_LocalT.Scale(Vector3f(Radius, Radius, Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Radius;
|
||||||
|
float Height;
|
||||||
|
int Axis;
|
||||||
AffineTransform m_LocalT;
|
AffineTransform m_LocalT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ set(MATH_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkQuadMesh.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkQuadMesh.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.cpp
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|
||||||
set(MATH_HEADERS
|
set(MATH_HEADERS
|
||||||
@@ -16,6 +17,7 @@ set(MATH_HEADERS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkTriangleMesh.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkQuadMesh.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkQuadMesh.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.h
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
|
|||||||
144
src/Vtk/Math/vtkCylinder.cpp
Normal file
144
src/Vtk/Math/vtkCylinder.cpp
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita’ degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
------------------------------------------------------------------
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3.0 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#include "Vtk/Math/vtkCylinder.h"
|
||||||
|
#include <vtkActor.h>
|
||||||
|
#include <vtkCylinderSource.h>
|
||||||
|
#include <vtkMatrix4x4.h>
|
||||||
|
#include <vtkPolyDataMapper.h>
|
||||||
|
#include <vtkProperty.h>
|
||||||
|
#include <vtkSmartPointer.h>
|
||||||
|
#include <vtkTransform.h>
|
||||||
|
#include "Math/vtkDense.h"
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Vtk {
|
||||||
|
|
||||||
|
vtkCylinder::vtkCylinder(vtkCylinder::Content *content)
|
||||||
|
: m_Actor(vtkActor::New()), m_Content(content) {
|
||||||
|
this->InstallPipe();
|
||||||
|
Object::connect(m_Content, &Content::Updated, this, &vtkCylinder::contentUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkCylinder::~vtkCylinder() {
|
||||||
|
m_Actor->Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtkCylinder::contentUpdate() {
|
||||||
|
if (!m_Content)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
||||||
|
if (!vmat) {
|
||||||
|
vtkNew<vtkMatrix4x4> mat;
|
||||||
|
root->SetUserMatrix(mat);
|
||||||
|
vmat = mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply the placement matrix by the volume scaling (Radius, Radius, Height)
|
||||||
|
Matrix4f transform = m_Content->GetMatrix() * m_Content->GetLocalMatrix();
|
||||||
|
Matrix4fToVtk(transform, vmat);
|
||||||
|
|
||||||
|
// Update internal alignment based on active axis
|
||||||
|
vtkTransform* alignment = vtkTransform::SafeDownCast(m_Actor->GetUserTransform());
|
||||||
|
if (alignment) {
|
||||||
|
alignment->Identity();
|
||||||
|
int axis = m_Content->GetAxis();
|
||||||
|
if (axis == 0) alignment->RotateZ(-90); // Y -> X
|
||||||
|
else if (axis == 1) ; // Y -> Y (identity)
|
||||||
|
else if (axis == 2) alignment->RotateX(90); // Y -> Z
|
||||||
|
|
||||||
|
// We keep it centered as per latest user preference in Step 677
|
||||||
|
// alignment->Translate(0, 0, 0); // Implicit
|
||||||
|
}
|
||||||
|
|
||||||
|
root->Modified();
|
||||||
|
Puppet::Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtkCylinder::Update() {
|
||||||
|
if (!m_Content) return;
|
||||||
|
|
||||||
|
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
||||||
|
if (!vmat) return;
|
||||||
|
|
||||||
|
Matrix4f fullTransform = VtkToMatrix4f(vmat);
|
||||||
|
Matrix4f placementScale = m_Content->GetLocalMatrix().inverse();
|
||||||
|
Matrix4f transform = fullTransform * placementScale;
|
||||||
|
|
||||||
|
if (m_Content->GetParent()) {
|
||||||
|
Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform;
|
||||||
|
m_Content->SetMatrix(localT);
|
||||||
|
} else {
|
||||||
|
m_Content->SetMatrix(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Content->Updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtkCylinder::InstallPipe() {
|
||||||
|
if (!m_Content)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vtkNew<vtkCylinderSource> cylinder;
|
||||||
|
cylinder->SetRadius(1.0);
|
||||||
|
cylinder->SetHeight(1.0);
|
||||||
|
cylinder->SetResolution(32);
|
||||||
|
|
||||||
|
vtkNew<vtkTransform> alignment;
|
||||||
|
alignment->Identity();
|
||||||
|
alignment->Translate(0, 0, -0.5);
|
||||||
|
|
||||||
|
// Default to Y alignment (Identity) as per latest request
|
||||||
|
int axis = m_Content->GetAxis();
|
||||||
|
if (axis == 0) alignment->RotateZ(-90);
|
||||||
|
else if (axis == 2) alignment->RotateX(90);
|
||||||
|
|
||||||
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
|
mapper->SetInputConnection(cylinder->GetOutputPort());
|
||||||
|
|
||||||
|
m_Actor->SetMapper(mapper);
|
||||||
|
m_Actor->SetUserTransform(alignment);
|
||||||
|
m_Actor->GetProperty()->SetRepresentationToWireframe();
|
||||||
|
m_Actor->GetProperty()->SetAmbient(0.6);
|
||||||
|
|
||||||
|
this->SetProp(m_Actor);
|
||||||
|
|
||||||
|
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||||
|
if (root) {
|
||||||
|
vtkNew<vtkMatrix4x4> vmat;
|
||||||
|
Matrix4fToVtk(m_Content->GetMatrix() * m_Content->GetLocalMatrix(), vmat);
|
||||||
|
root->SetUserMatrix(vmat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vtk
|
||||||
|
} // namespace uLib
|
||||||
67
src/Vtk/Math/vtkCylinder.h
Normal file
67
src/Vtk/Math/vtkCylinder.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita’ degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
------------------------------------------------------------------
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3.0 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#ifndef U_VTKCYLINDER_H
|
||||||
|
#define U_VTKCYLINDER_H
|
||||||
|
|
||||||
|
#include "Math/Cylinder.h"
|
||||||
|
#include "Vtk/uLibVtkInterface.h"
|
||||||
|
#include <vtkActor.h>
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Vtk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief VTK representation of the uLib::Cylinder object.
|
||||||
|
*
|
||||||
|
* This class wraps a vtkCylinderSource and synchronizes it with the
|
||||||
|
* mathematical state of a Cylinder object. It manages the alignment
|
||||||
|
* between VTK's Y-centered cylinder and uLib's Z-based coordinate system.
|
||||||
|
*/
|
||||||
|
class vtkCylinder : public Puppet {
|
||||||
|
typedef Cylinder Content;
|
||||||
|
|
||||||
|
public:
|
||||||
|
vtkCylinder(Content *content);
|
||||||
|
virtual ~vtkCylinder();
|
||||||
|
|
||||||
|
/** Synchronizes the VTK actor with the uLib model matrix */
|
||||||
|
virtual void contentUpdate();
|
||||||
|
|
||||||
|
/** Synchronizes the uLib model matrix with the VTK actor (e.g., after UI manipulation) */
|
||||||
|
virtual void Update();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Sets up the VTK visualization pipeline */
|
||||||
|
virtual void InstallPipe();
|
||||||
|
|
||||||
|
vtkActor *m_Actor;
|
||||||
|
Content *m_Content;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vtk
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif // U_VTKCYLINDER_H
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "vtkObjectsContext.h"
|
#include "vtkObjectsContext.h"
|
||||||
#include "vtkContainerBox.h"
|
#include "Vtk/vtkContainerBox.h"
|
||||||
|
#include "Vtk/Math/vtkCylinder.h"
|
||||||
#include "HEP/Detectors/vtkDetectorChamber.h"
|
#include "HEP/Detectors/vtkDetectorChamber.h"
|
||||||
|
|
||||||
#include <vtkAssembly.h>
|
#include <vtkAssembly.h>
|
||||||
@@ -128,6 +129,8 @@ Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
|
|||||||
return new vtkContainerBox(static_cast<uLib::ContainerBox*>(obj));
|
return new vtkContainerBox(static_cast<uLib::ContainerBox*>(obj));
|
||||||
} else if (std::strcmp(className, "DetectorChamber") == 0) {
|
} else if (std::strcmp(className, "DetectorChamber") == 0) {
|
||||||
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
|
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
|
||||||
|
} else if (std::strcmp(className, "Cylinder") == 0) {
|
||||||
|
return new vtkCylinder(static_cast<uLib::Cylinder*>(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