Compare commits
8 Commits
9118afdd13
...
andrea-geo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6396bdfebf | ||
|
|
96ab3b0930 | ||
|
|
5c04d00d4c | ||
|
|
72e69cfca5 | ||
|
|
59a9e829fc | ||
|
|
6068b62e39 | ||
|
|
4435776484 | ||
|
|
a1c5fc2600 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,3 +13,7 @@ src/Python/uLib/*.pyd
|
||||
src/Python/uLib/*.pyc
|
||||
src/Python/uLib/__pycache__
|
||||
src/Python/uLib/.nfs*
|
||||
test_props.xml
|
||||
test_props2.xml
|
||||
test_boost.cpp
|
||||
.claude/settings.json
|
||||
|
||||
@@ -38,7 +38,7 @@ endif()
|
||||
|
||||
# The version number.
|
||||
set(PROJECT_VERSION_MAJOR 0)
|
||||
set(PROJECT_VERSION_MINOR 6)
|
||||
set(PROJECT_VERSION_MINOR 7)
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
set(PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
|
||||
|
||||
@@ -448,17 +448,17 @@ void PropertyEditor::setObject(::uLib::Object* obj, bool displayOnly) {
|
||||
}
|
||||
} else {
|
||||
// Priority 2: Standard factory lookup
|
||||
auto it = m_Factories.find(prop->GetTypeIndex());
|
||||
if (it != m_Factories.end()) {
|
||||
widget = it->second(prop, m_Container);
|
||||
} else {
|
||||
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;
|
||||
|
||||
widget = new PropertyWidgetBase(prop, m_Container);
|
||||
widget = new PropertyWidgetBase(prop, m_Container);
|
||||
widget->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
|
||||
@@ -19,3 +19,76 @@ The vtkHandlerWidget should handle the transformation of the puppet internal Con
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## ACTIVATE PROPERTIES
|
||||
|
||||
ULIB_ACTIVATE_PROPERTIES must run after all member initialization, with the vtable pointing to the most-derived type. This is why it has to be in each constructor — in C++, virtual dispatch only works correctly after a class's vtable is installed, which happens at the start of each level's constructor body.
|
||||
|
||||
### Option 1 — End-of-class macro (no constructor boilerplate)
|
||||
Declare a private member activator as the last member of the class. Its constructor runs after all other members, and at that point the vtable is already Derived's:
|
||||
|
||||
|
||||
// In Property.h, add alongside ULIB_ACTIVATE_PROPERTIES:
|
||||
#define ULIB_DECLARE_PROPERTIES(SelfType) \
|
||||
private: \
|
||||
struct _PropActivator { \
|
||||
_PropActivator(SelfType* self) { \
|
||||
uLib::Archive::property_register_archive ar(self); \
|
||||
ar & *self; \
|
||||
} \
|
||||
} _prop_activator{this};
|
||||
Usage in ContainerBox.h — place it just before the closing brace:
|
||||
|
||||
|
||||
class ContainerBox : public TRS {
|
||||
public:
|
||||
// ... all constructors, no more ULIB_ACTIVATE_PROPERTIES(*this)
|
||||
|
||||
ULIB_DECLARE_PROPERTIES(ContainerBox) // ← replaces all 3 constructor calls
|
||||
};
|
||||
Tradeoff: Works perfectly for single-level classes. For hierarchies where multiple levels use the macro, RegisterDynamicProperty must deduplicate by name (skip if already registered). Requires one line per class in the class body, but zero lines in constructors.
|
||||
|
||||
### Option 2 — Lazy init via virtual InitProperties() in Object
|
||||
Modify Object to call a virtual hook on first GetProperties():
|
||||
|
||||
|
||||
// In Object.h:
|
||||
class Object {
|
||||
protected:
|
||||
virtual void InitProperties() {} // override in derived
|
||||
public:
|
||||
const std::vector<PropertyBase*>& GetProperties() const {
|
||||
if (!m_propertiesInitialized) {
|
||||
const_cast<Object*>(this)->m_propertiesInitialized = true;
|
||||
const_cast<Object*>(this)->InitProperties();
|
||||
}
|
||||
return m_properties;
|
||||
}
|
||||
};
|
||||
Then a CRTP base handles the rest without any macro:
|
||||
|
||||
|
||||
template<typename Derived>
|
||||
class PropertyObject : public Object {
|
||||
protected:
|
||||
void InitProperties() override {
|
||||
uLib::Archive::property_register_archive ar(this);
|
||||
ar & *static_cast<Derived*>(this);
|
||||
}
|
||||
};
|
||||
Usage — just change the base class:
|
||||
|
||||
|
||||
class ContainerBox : public PropertyObject<ContainerBox>, public TRS { ... };
|
||||
// Nothing else needed — properties activated on first GetProperties() call
|
||||
Tradeoff: Most "automatic" — pure inheritance, no constructor or class-body macros. But requires modifying Object (adding m_propertiesInitialized flag + virtual hook), and lazy init means properties aren't available until first access. Also doesn't work well with multiple inheritance (which TRS likely involves).
|
||||
|
||||
Option 3 — CRTP doesn't work from the base constructor
|
||||
Just to be explicit: a CRTP base that calls ULIB_ACTIVATE_PROPERTIES in its own constructor won't work, because when PropertyObject<Derived>'s constructor runs, the vtable is PropertyObject<Derived>'s — Derived::serialize() hasn't been installed yet. So ar & *self calls Object::serialize() (a no-op).
|
||||
|
||||
Recommendation
|
||||
Option 1 is the least invasive and safest. Add deduplication to RegisterDynamicProperty in Object.cpp to guard against re-registration when hierarchies stack activators, then replace every ULIB_ACTIVATE_PROPERTIES(*this) in constructors with a single ULIB_DECLARE_PROPERTIES(ClassName) at the end of the class body.
|
||||
|
||||
Option 2 is cleaner to use but requires changing the Object interface and has the lazy-init semantic change — only worth it if you want zero-touch activation across the entire framework.
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include <boost/archive/detail/basic_pointer_iserializer.hpp>
|
||||
#include <boost/archive/detail/basic_pointer_oserializer.hpp>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
@@ -309,18 +311,32 @@ namespace Archive {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XML //
|
||||
|
||||
// ULIB_SERIALIZATION_VERSION should be get from the build system
|
||||
#ifndef ULIB_SERIALIZATION_VERSION
|
||||
#define ULIB_SERIALIZATION_VERSION "0.0"
|
||||
#endif
|
||||
|
||||
class xml_iarchive : public boost::archive::xml_iarchive_impl<xml_iarchive> {
|
||||
typedef xml_iarchive Archive;
|
||||
typedef boost::archive::xml_iarchive_impl<Archive> base;
|
||||
|
||||
unsigned int m_flags;
|
||||
|
||||
// give serialization implementation access to this class
|
||||
friend class boost::archive::detail::interface_iarchive<Archive>;
|
||||
friend class boost::archive::basic_xml_iarchive<Archive>;
|
||||
friend class boost::archive::load_access;
|
||||
|
||||
public:
|
||||
xml_iarchive(std::istream &is, unsigned int flags = 0)
|
||||
: xml_iarchive_impl<xml_iarchive>(is, flags) {}
|
||||
: boost::archive::xml_iarchive_impl<xml_iarchive>(
|
||||
is, flags | boost::archive::no_header), m_flags(flags) {
|
||||
if (0 == (flags & boost::archive::no_header)) {
|
||||
std::string line;
|
||||
std::getline(is, line); // <?xml ... ?>
|
||||
std::getline(is, line); // <!DOCTYPE ...>
|
||||
std::getline(is, line); // <ulib_serialization ...>
|
||||
}
|
||||
}
|
||||
|
||||
using basic_xml_iarchive::load_override;
|
||||
|
||||
@@ -368,14 +384,31 @@ class xml_oarchive : public boost::archive::xml_oarchive_impl<xml_oarchive> {
|
||||
typedef xml_oarchive Archive;
|
||||
typedef boost::archive::xml_oarchive_impl<Archive> base;
|
||||
|
||||
unsigned int m_flags;
|
||||
|
||||
// give serialization implementation access to this class
|
||||
friend class boost::archive::detail::interface_oarchive<Archive>;
|
||||
friend class boost::archive::basic_xml_oarchive<Archive>;
|
||||
friend class boost::archive::save_access;
|
||||
|
||||
public:
|
||||
xml_oarchive(std::ostream &os, unsigned int flags = 0)
|
||||
: boost::archive::xml_oarchive_impl<xml_oarchive>(os, flags) {}
|
||||
: boost::archive::xml_oarchive_impl<xml_oarchive>(
|
||||
os, flags | boost::archive::no_header), m_flags(flags) {
|
||||
if (0 == (flags & boost::archive::no_header)) {
|
||||
this->This()->put(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n");
|
||||
this->This()->put("<!DOCTYPE ulib_serialization>\n");
|
||||
this->This()->put("<ulib_serialization signature=\"serialization::archive\" ");
|
||||
this->write_attribute("version", (const char *)ULIB_SERIALIZATION_VERSION);
|
||||
this->This()->put(">\n");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~xml_oarchive() {
|
||||
if (0 == (m_flags & boost::archive::no_header)) {
|
||||
this->This()->put("</ulib_serialization>\n");
|
||||
}
|
||||
}
|
||||
|
||||
using basic_xml_oarchive::save_override;
|
||||
|
||||
@@ -397,8 +430,6 @@ public:
|
||||
// Do not save any human decoration string //
|
||||
// basic_text_oprimitive::save(str);
|
||||
}
|
||||
|
||||
virtual ~xml_oarchive() {}
|
||||
};
|
||||
|
||||
// typedef boost::archive::detail::polymorphic_oarchive_route<
|
||||
|
||||
@@ -58,6 +58,7 @@ if(USE_CUDA)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${libname} ${LIBRARIES})
|
||||
target_compile_definitions(${libname} PUBLIC ULIB_SERIALIZATION_VERSION="${PROJECT_VERSION}")
|
||||
|
||||
install(TARGETS ${libname}
|
||||
EXPORT "uLibTargets"
|
||||
|
||||
@@ -79,6 +79,7 @@ void Object::RegisterDynamicProperty(PropertyBase* prop) {
|
||||
if (prop) {
|
||||
for (auto* existing : d->m_DynamicProperties) {
|
||||
if (existing == prop) return;
|
||||
if (existing->GetQualifiedName() == prop->GetQualifiedName()) return;
|
||||
}
|
||||
d->m_DynamicProperties.push_back(prop);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ public:
|
||||
Object(const Object ©);
|
||||
virtual ~Object();
|
||||
|
||||
virtual const char * GetClassName() const { return "Object"; }
|
||||
virtual const char * GetClassName() const { return type_name(); }
|
||||
virtual const char * type_name() const { return "Object"; }
|
||||
|
||||
const std::string& GetInstanceName() const;
|
||||
void SetInstanceName(const std::string& name);
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
ObjectsContext();
|
||||
virtual ~ObjectsContext();
|
||||
|
||||
virtual const char * GetClassName() const { return "ObjectsContext"; }
|
||||
uLibTypeMacro(ObjectsContext, Object)
|
||||
virtual ObjectsContext* GetChildren() override { return this; }
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,13 +54,13 @@ public:
|
||||
virtual void Updated() override { ULIB_SIGNAL_EMIT(PropertyBase::Updated); }
|
||||
|
||||
// Serialization support for different uLib archives
|
||||
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::text_oarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::text_iarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::log_archive & ar, const unsigned int version) = 0;
|
||||
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::text_oarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::text_iarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int version) override = 0;
|
||||
virtual void serialize(Archive::log_archive & ar, const unsigned int version) override = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -407,12 +407,32 @@ private:
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience macro to automatically activate and register all HRP members
|
||||
* @brief Convenience macro to automatically activate and register all HRP members
|
||||
* as uLib properties. Usage: ULIB_ACTIVATE_PROPERTIES(obj)
|
||||
*/
|
||||
#define ULIB_ACTIVATE_PROPERTIES(obj) \
|
||||
{ uLib::Archive::property_register_archive _ar_tmp(&(obj)); _ar_tmp & (obj); }
|
||||
|
||||
/**
|
||||
* @brief Declares a private member that automatically calls ULIB_ACTIVATE_PROPERTIES
|
||||
* in every constructor of the class. Place this macro as the last declaration
|
||||
* inside the class body (before the closing brace).
|
||||
*
|
||||
* Usage: ULIB_DECLARE_PROPERTIES(ClassName)
|
||||
*
|
||||
* This replaces per-constructor ULIB_ACTIVATE_PROPERTIES(*this) calls.
|
||||
* RegisterDynamicProperty deduplicates by qualified name, so re-registration
|
||||
* from inherited activators in a hierarchy is safe.
|
||||
*/
|
||||
#define ULIB_DECLARE_PROPERTIES(SelfType) \
|
||||
private: \
|
||||
struct _PropActivator { \
|
||||
_PropActivator(SelfType* self) { \
|
||||
uLib::Archive::property_register_archive _ar(self); \
|
||||
_ar & *self; \
|
||||
} \
|
||||
} _prop_activator{this};
|
||||
|
||||
} // namespace Archive
|
||||
} // namespace uLib
|
||||
|
||||
|
||||
@@ -309,6 +309,8 @@ namespace uLib {
|
||||
#define HRP5(name, data, units, min, max) boost::serialization::make_hrp(name, data, units).range(min, max)
|
||||
#define HRP6(name, data, units, default, min, max) boost::serialization::make_hrp(name, data, units).set_default(default).range(min, max)
|
||||
|
||||
#define HRPE(name, data, labels) boost::serialization::make_hrp_enum(name, data, labels)
|
||||
|
||||
// LEFT FOR BACKWARD COMPATIBILITY
|
||||
#define HRPU(name, units) boost::serialization::make_hrp(BOOST_PP_STRINGIZE(name), name, units)
|
||||
|
||||
@@ -349,7 +351,7 @@ using boost::serialization::make_hrp_enum;
|
||||
#define ULIB_SERIALIZE_OBJECT(_Ob, ...) \
|
||||
_ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_OBJECT(_Ob, __VA_ARGS__)
|
||||
#define AR(_name) _ULIB_DETAIL_UNINTRUSIVE_AR_(_name)
|
||||
#define HR(_name) _ULIB_DETAIL_UNINTRUSIVE_AR_(_name)
|
||||
#define HR(_name) _ULIB_DETAIL_UNINTRUSIVE_HR_(_name)
|
||||
#endif
|
||||
|
||||
#define ULIB_SERIALIZE_ACCESS \
|
||||
@@ -362,14 +364,14 @@ using boost::serialization::make_hrp_enum;
|
||||
#define ULIB_CLASS_EXPORT_OBJECT_KEY(_FullNamespaceClass) \
|
||||
BOOST_CLASS_EXPORT_KEY(_FullNamespaceClass)
|
||||
|
||||
#define _SERIALIZE_IMPL_SEQ \
|
||||
(uLib::Archive::text_iarchive)(uLib::Archive::text_oarchive)( \
|
||||
uLib::Archive:: \
|
||||
hrt_iarchive)(uLib::Archive:: \
|
||||
hrt_oarchive)(uLib::Archive:: \
|
||||
xml_iarchive)(uLib::Archive:: \
|
||||
xml_oarchive)(uLib::Archive:: \
|
||||
log_archive)
|
||||
#define _SERIALIZE_IMPL_SEQ \
|
||||
(uLib::Archive::text_iarchive) \
|
||||
(uLib::Archive::text_oarchive) \
|
||||
(uLib::Archive::hrt_iarchive) \
|
||||
(uLib::Archive::hrt_oarchive) \
|
||||
(uLib::Archive::xml_iarchive) \
|
||||
(uLib::Archive::xml_oarchive) \
|
||||
(uLib::Archive::log_archive)
|
||||
|
||||
/** Solving virtual class check problem */
|
||||
#define _ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE(_Base, _Derived) \
|
||||
@@ -549,7 +551,8 @@ using boost::serialization::make_hrp_enum;
|
||||
void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int v) { \
|
||||
/* PP serialize */ BOOST_PP_SEQ_FOR_EACH( \
|
||||
_UNAR_OP, ob, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))); \
|
||||
/* MPL serialize */ /*uLib::mpl::for_each<_Ob::BaseList>(uLib::detail::Serializable::serialize_baseobject<_Ob,ArchiveT>(ob,ar) );*/ } \
|
||||
/* MPL serialize */ /*uLib::mpl::for_each<_Ob::BaseList> \
|
||||
(uLib::detail::Serializable::serialize_baseobject<_Ob,ArchiveT>(ob,ar) );*/ }\
|
||||
template <class ArchiveT> \
|
||||
inline void load_construct_data(ArchiveT &ar, _Ob *ob, \
|
||||
const unsigned int file_version) { \
|
||||
@@ -572,10 +575,18 @@ using boost::serialization::make_hrp_enum;
|
||||
_SERIALIZE_IMPL_SEQ) \
|
||||
template <class ArchiveT> \
|
||||
void boost::serialization::access2<_Ob>::save_override( \
|
||||
ArchiveT &ar, _Ob &ob, const unsigned int version)
|
||||
ArchiveT &ar, _Ob &ob, const unsigned int version)
|
||||
|
||||
|
||||
#define _ULIB_DETAIL_UNINTRUSIVE_AR_(name) \
|
||||
boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), ob.name)
|
||||
#define _ULIB_DETAIL_UNINTRUSIVE_HR_(name) \
|
||||
boost::serialization::make_hrp(BOOST_PP_STRINGIZE(name), ob.name)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -76,8 +76,9 @@ public:
|
||||
|
||||
ULIB_SERIALIZABLE_OBJECT(TestObject2)
|
||||
ULIB_SERIALIZE_OBJECT(TestObject2, TestObject) {
|
||||
// std::cout << "Serializing TestObject2" << std::endl;
|
||||
ar & boost::serialization::make_hrp("value2", ob.m_Value2, "mm").set_default(1.);
|
||||
std::cout << "Serializing TestObject2" << std::endl;
|
||||
// ar & boost::serialization::make_hrp("value2", ob.m_Value2, "mm").set_default(1.);
|
||||
ar & HRP("value2", ob.m_Value2, "mm").set_default(1.);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,13 +8,12 @@ using namespace uLib;
|
||||
|
||||
class TestObject : public Object {
|
||||
public:
|
||||
uLibTypeMacro(TestObject, Object)
|
||||
TestObject() : Object(),
|
||||
IntProp(this, "IntProp", 10),
|
||||
StringProp(this, "StringProp", "Initial")
|
||||
{}
|
||||
|
||||
virtual const char* GetClassName() const override { return "TestObject"; }
|
||||
|
||||
Property<int> IntProp;
|
||||
Property<std::string> StringProp;
|
||||
};
|
||||
|
||||
@@ -9,10 +9,9 @@ using namespace uLib;
|
||||
|
||||
class TestObject : public Object {
|
||||
public:
|
||||
uLibTypeMacro(TestObject, Object)
|
||||
TestObject() : Object() {}
|
||||
|
||||
virtual const char* GetClassName() const override { return "TestObject"; }
|
||||
|
||||
// Use new typedefs
|
||||
StringProperty StringProp = StringProperty(this, "StringProp", "Initial");
|
||||
IntProperty IntProp = IntProperty(this, "IntProp", 42);
|
||||
|
||||
@@ -39,13 +39,11 @@ namespace uLib {
|
||||
|
||||
|
||||
class DetectorChamber : public ContainerBox {
|
||||
|
||||
typedef ContainerBox BaseClass;
|
||||
|
||||
|
||||
public:
|
||||
uLibTypeMacro(DetectorChamber, ContainerBox)
|
||||
|
||||
virtual const char * GetClassName() const { return "DetectorChamber"; }
|
||||
|
||||
|
||||
DetectorChamber() : BaseClass() {
|
||||
m_ProjectionPlane.origin = HPoint3f(0, 0, 0);
|
||||
|
||||
@@ -26,8 +26,7 @@ namespace Geant {
|
||||
class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public AffineTransform
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.EmitterPrimary"; }
|
||||
uLibTypeMacro(EmitterPrimary, Object)
|
||||
|
||||
EmitterPrimary();
|
||||
virtual ~EmitterPrimary();
|
||||
@@ -47,8 +46,7 @@ class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public AffineTransf
|
||||
class SkyPlaneEmitterPrimary : public EmitterPrimary
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.SkyPlaneEmitterPrimary"; }
|
||||
uLibTypeMacro(SkyPlaneEmitterPrimary, EmitterPrimary)
|
||||
|
||||
SkyPlaneEmitterPrimary();
|
||||
virtual ~SkyPlaneEmitterPrimary();
|
||||
@@ -69,8 +67,7 @@ class SkyPlaneEmitterPrimary : public EmitterPrimary
|
||||
class CylinderEmitterPrimary : public EmitterPrimary
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.CylinderEmitterPrimary"; }
|
||||
uLibTypeMacro(CylinderEmitterPrimary, EmitterPrimary)
|
||||
|
||||
CylinderEmitterPrimary();
|
||||
virtual ~CylinderEmitterPrimary();
|
||||
@@ -98,8 +95,7 @@ class CylinderEmitterPrimary : public EmitterPrimary
|
||||
class QuadMeshEmitterPrimary : public EmitterPrimary
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.QuadMeshEmitterPrimary"; }
|
||||
uLibTypeMacro(QuadMeshEmitterPrimary, EmitterPrimary)
|
||||
|
||||
QuadMeshEmitterPrimary();
|
||||
virtual ~QuadMeshEmitterPrimary();
|
||||
|
||||
@@ -50,8 +50,7 @@ class SteppingAction;
|
||||
class GeantEvent : public Object {
|
||||
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.GeantEvent"; }
|
||||
uLibTypeMacro(GeantEvent, Object)
|
||||
|
||||
/// A single interaction step along the muon path.
|
||||
struct Delta {
|
||||
|
||||
@@ -60,6 +60,7 @@ private:
|
||||
|
||||
class Material : public Object {
|
||||
public:
|
||||
uLibTypeMacro(Material, Object)
|
||||
|
||||
enum State {
|
||||
Undefined = 0,
|
||||
@@ -68,8 +69,6 @@ public:
|
||||
Gas
|
||||
};
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.Material"; }
|
||||
|
||||
Material();
|
||||
Material(const char *name);
|
||||
~Material();
|
||||
|
||||
@@ -43,8 +43,7 @@ class EmitterPrimary;
|
||||
|
||||
class Scene : public Object {
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.Scene"; }
|
||||
uLibTypeMacro(Scene, Object)
|
||||
|
||||
Scene();
|
||||
~Scene();
|
||||
|
||||
@@ -43,8 +43,7 @@ namespace Geant {
|
||||
|
||||
class Solid : public Object {
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.Solid"; }
|
||||
uLibTypeMacro(Solid, Object)
|
||||
|
||||
Solid();
|
||||
Solid(const char *name);
|
||||
@@ -93,10 +92,8 @@ protected:
|
||||
|
||||
|
||||
class TessellatedSolid : public Solid {
|
||||
typedef Solid BaseClass;
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.TessellatedSolid"; }
|
||||
uLibTypeMacro(TessellatedSolid, Solid)
|
||||
|
||||
TessellatedSolid();
|
||||
TessellatedSolid(const char *name);
|
||||
@@ -120,11 +117,9 @@ private :
|
||||
|
||||
|
||||
class BoxSolid : public Solid {
|
||||
typedef Solid BaseClass;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
virtual const char* GetClassName() const override { return "Geant.BoxSolid"; }
|
||||
uLibTypeMacro(BoxSolid, Solid)
|
||||
|
||||
BoxSolid(const char *name = "");
|
||||
BoxSolid(const char *name, ContainerBox *box);
|
||||
|
||||
@@ -26,7 +26,6 @@ Assembly::Assembly()
|
||||
m_BBoxMax(Vector3f::Zero()),
|
||||
m_ShowBoundingBox(false),
|
||||
m_GroupSelection(true) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
}
|
||||
|
||||
Assembly::Assembly(const Assembly ©)
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace uLib {
|
||||
class Assembly : public ObjectsContext, public TRS {
|
||||
public:
|
||||
uLibTypeMacro(Assembly, ObjectsContext, TRS)
|
||||
virtual const char *GetClassName() const override { return "Assembly"; }
|
||||
|
||||
|
||||
Assembly();
|
||||
Assembly(const Assembly ©);
|
||||
@@ -113,6 +113,8 @@ private:
|
||||
bool m_GroupSelection;
|
||||
bool m_InUpdated = false;
|
||||
std::map<Object*, Connection> m_ChildConnections;
|
||||
|
||||
ULIB_DECLARE_PROPERTIES(Assembly)
|
||||
};
|
||||
|
||||
} // namespace uLib
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Geometry.h"
|
||||
#include "Core/Object.h"
|
||||
#include "Core/Property.h"
|
||||
#include "Core/Serializable.h"
|
||||
#include "Math/Dense.h"
|
||||
#include "Math/Transform.h"
|
||||
#include <utility>
|
||||
@@ -48,16 +49,11 @@ namespace uLib {
|
||||
*/
|
||||
class ContainerBox : public TRS {
|
||||
|
||||
public:
|
||||
uLibTypeMacro(ContainerBox, TRS)
|
||||
ULIB_SERIALIZE_ACCESS
|
||||
ULIB_DECLARE_PROPERTIES(ContainerBox)
|
||||
|
||||
virtual const char * GetClassName() const override { return "ContainerBox"; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// PROPERTIES //
|
||||
|
||||
Vector3f Size;
|
||||
Vector3f Origin;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
@@ -67,7 +63,6 @@ public:
|
||||
: m_LocalT(this), // BaseClass is Parent of m_LocalTransform
|
||||
Size(1.0f, 1.0f, 1.0f),
|
||||
Origin(0.0f, 0.0f, 0.0f) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
@@ -79,7 +74,6 @@ public:
|
||||
: m_LocalT(this),
|
||||
Size(size),
|
||||
Origin(0.0f, 0.0f, 0.0f) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
@@ -92,13 +86,12 @@ public:
|
||||
TRS(copy),
|
||||
Size(copy.Size),
|
||||
Origin(copy.Origin) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialization template for property registration and persistence.
|
||||
*/
|
||||
// /**
|
||||
// * @brief Serialization template for property registration and persistence.
|
||||
// */
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & HRP(Size);
|
||||
@@ -236,9 +229,13 @@ private:
|
||||
|
||||
|
||||
private:
|
||||
Vector3f Size;
|
||||
Vector3f Origin;
|
||||
AffineTransform m_LocalT;
|
||||
|
||||
};
|
||||
|
||||
} // namespace uLib
|
||||
|
||||
|
||||
#endif // CONTAINERBOX_H
|
||||
|
||||
@@ -41,8 +41,10 @@ namespace uLib {
|
||||
*/
|
||||
class Cylinder : public TRS {
|
||||
|
||||
public:
|
||||
uLibTypeMacro(Cylinder, TRS)
|
||||
ULIB_DECLARE_PROPERTIES(Cylinder)
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief PROPERTIES
|
||||
@@ -51,22 +53,20 @@ public:
|
||||
float Height;
|
||||
int Axis;
|
||||
|
||||
virtual const char * GetClassName() const override { return "Cylinder"; }
|
||||
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Aligns with Y by default.
|
||||
*/
|
||||
Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor with radius and height.
|
||||
*/
|
||||
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) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
*/
|
||||
Cylinder(const Cylinder ©)
|
||||
: m_LocalT(this), TRS(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) {
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
@@ -84,10 +83,10 @@ public:
|
||||
*/
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & boost::serialization::make_nvp("TRS", boost::serialization::base_object<TRS>(*this));
|
||||
ar & HRP(Radius);
|
||||
ar & HRP(Height);
|
||||
ar & HRP(Axis);
|
||||
ar & boost::serialization::make_hrp_enum("Axis", Axis, {"X", "Y", "Z"});
|
||||
ar & NVP("TRS", boost::serialization::base_object<TRS>(*this));
|
||||
}
|
||||
|
||||
/** Sets the radius of the cylinder */
|
||||
|
||||
@@ -43,7 +43,7 @@ protected:
|
||||
public:
|
||||
uLibTypeMacro(Geometry, Object)
|
||||
|
||||
virtual const char * GetClassName() const override { return "Geometry"; }
|
||||
|
||||
|
||||
virtual void SetParent(Geometry* p) { m_Parent = p; }
|
||||
virtual Geometry* GetParent() const { return m_Parent; }
|
||||
@@ -93,7 +93,7 @@ protected:
|
||||
public:
|
||||
uLibTypeMacro(LinearGeometry, Geometry)
|
||||
|
||||
virtual const char * GetClassName() const override { return "LinearGeometry"; }
|
||||
|
||||
|
||||
virtual bool IsLinear() const override { return true; }
|
||||
virtual bool IsPure() const override { return true; }
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
uLibTypeMacro(CylindricalGeometry, LinearGeometry)
|
||||
CylindricalGeometry() {}
|
||||
|
||||
virtual const char * GetClassName() const override { return "CylindricalGeometry"; }
|
||||
|
||||
|
||||
virtual bool IsPure() const override { return false; }
|
||||
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
uLibTypeMacro(SphericalGeometry, LinearGeometry)
|
||||
SphericalGeometry() {}
|
||||
|
||||
virtual const char * GetClassName() const override { return "SphericalGeometry"; }
|
||||
|
||||
|
||||
virtual bool IsPure() const override { return false; }
|
||||
|
||||
@@ -212,7 +212,7 @@ public:
|
||||
uLibTypeMacro(ToroidalGeometry, LinearGeometry)
|
||||
ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {}
|
||||
|
||||
virtual const char * GetClassName() const override { return "ToroidalGeometry"; }
|
||||
|
||||
|
||||
virtual bool IsPure() const override { return false; }
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
SUBDIRS = .
|
||||
|
||||
include $(top_srcdir)/Common.am
|
||||
|
||||
library_includedir = $(includedir)/libmutom-${PACKAGE_VERSION}/Math
|
||||
library_include_HEADERS = ContainerBox.h \
|
||||
Dense.h \
|
||||
Geometry.h \
|
||||
Transform.h \
|
||||
StructuredData.h\
|
||||
StructuredGrid.h\
|
||||
VoxImage.h \
|
||||
VoxRaytracer.h \
|
||||
Utils.h \
|
||||
VoxImageFilter.h\
|
||||
VoxImageFilter.hpp \
|
||||
VoxImageFilterLinear.hpp \
|
||||
VoxImageFilterMedian.hpp \
|
||||
VoxImageFilterABTrim.hpp \
|
||||
VoxImageFilterBilateral.hpp \
|
||||
VoxImageFilterThreshold.hpp \
|
||||
VoxImageFilter2ndStat.hpp \
|
||||
VoxImageFilterCustom.hpp \
|
||||
Accumulator.h \
|
||||
TriangleMesh.h
|
||||
|
||||
|
||||
_MATH_SOURCES = \
|
||||
VoxRaytracer.cpp \
|
||||
StructuredData.cpp \
|
||||
StructuredGrid.cpp \
|
||||
VoxImage.cpp \
|
||||
TriangleMesh.cpp \
|
||||
Dense.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
noinst_LTLIBRARIES = libmutommath.la
|
||||
libmutommath_la_SOURCES = ${_MATH_SOURCES}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class Polydata : public Object {
|
||||
|
||||
public:
|
||||
|
||||
virtual const char * GetClassName() const { return "Polydata"; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class QuadMesh : public TRS
|
||||
public:
|
||||
uLibTypeMacro(QuadMesh, TRS)
|
||||
|
||||
virtual const char * GetClassName() const override { return "QuadMesh"; }
|
||||
|
||||
|
||||
void PrintSelf(std::ostream &o);
|
||||
|
||||
|
||||
@@ -188,9 +188,12 @@ public:
|
||||
typedef Eigen::Affine3f AffineMatrix;
|
||||
|
||||
class TRS : public AffineTransform {
|
||||
|
||||
public:
|
||||
|
||||
uLibTypeMacro(TRS, AffineTransform)
|
||||
ULIB_SERIALIZE_ACCESS
|
||||
// ULIB_DECLARE_PROPERTIES(TRS)
|
||||
|
||||
public:
|
||||
|
||||
Vector3f position = Vector3f::Zero();
|
||||
Vector3f rotation = Vector3f::Zero();
|
||||
@@ -259,6 +262,7 @@ public:
|
||||
ar & HRPU(rotation, "rad");
|
||||
ar & HRP(scaling);
|
||||
}
|
||||
|
||||
|
||||
AffineMatrix GetAffineMatrix() const {
|
||||
AffineMatrix m = AffineMatrix::Identity();
|
||||
@@ -273,12 +277,26 @@ public:
|
||||
Matrix4f GetMatrix() const {
|
||||
return this->GetAffineMatrix().matrix();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const TRS& trs) {
|
||||
os << trs.position << " " << trs.rotation << " " << trs.scaling;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::istream& operator>>(std::istream& is, TRS& trs) {
|
||||
is >> trs.position >> trs.rotation >> trs.scaling;
|
||||
return is;
|
||||
}
|
||||
|
||||
} // uLib
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class TriangleMesh : public TRS
|
||||
public:
|
||||
uLibTypeMacro(TriangleMesh, TRS)
|
||||
|
||||
virtual const char * GetClassName() const override { return "TriangleMesh"; }
|
||||
|
||||
|
||||
void PrintSelf(std::ostream &o);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Abstract {
|
||||
class VoxImage : public uLib::StructuredGrid {
|
||||
public:
|
||||
|
||||
virtual const char * GetClassName() const { return "VoxImage"; }
|
||||
|
||||
|
||||
typedef uLib::StructuredGrid BaseClass;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ class VoxImageFilter : public Abstract::VoxImageFilter, public Object {
|
||||
|
||||
public:
|
||||
|
||||
virtual const char * GetClassName() const { return "VoxImageFilter"; }
|
||||
|
||||
|
||||
VoxImageFilter(const Vector3i &size);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class vtkObjectsContext; // forward
|
||||
*/
|
||||
class Assembly : public Puppet {
|
||||
public:
|
||||
virtual const char *GetClassName() const override { return "Vtk.Assembly"; }
|
||||
uLibTypeMacro(Assembly, Puppet)
|
||||
|
||||
Assembly(uLib::Assembly *content);
|
||||
virtual ~Assembly();
|
||||
|
||||
@@ -111,17 +111,17 @@ void vtkContainerBox::SyncFromVtk() {
|
||||
|
||||
// VTK -> Model: Extract new world TRS from proxy, which matches the model's TRS center
|
||||
vtkMatrix4x4* rootMat = root->GetUserMatrix();
|
||||
if (rootMat) {
|
||||
std::cout << "[vtkContainerBox::SyncFromVtk] Read Proxy UserMatrix:" << std::endl;
|
||||
rootMat->Print(std::cout);
|
||||
}
|
||||
// if (rootMat) {
|
||||
// std::cout << "[vtkContainerBox::SyncFromVtk] Read Proxy UserMatrix:" << std::endl;
|
||||
// rootMat->Print(std::cout);
|
||||
// }
|
||||
|
||||
Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
|
||||
|
||||
// Synchronize TRS property members from the updated local matrix
|
||||
m_Content->FromMatrix(vtkWorld);
|
||||
|
||||
std::cout << "[vtkContainerBox::SyncFromVtk] New Model WorldMatrix:" << std::endl << m_Content->GetWorldMatrix() << std::endl;
|
||||
// std::cout << "[vtkContainerBox::SyncFromVtk] New Model WorldMatrix:" << std::endl << m_Content->GetWorldMatrix() << std::endl;
|
||||
|
||||
// Since we modified the model, notify observers, but block the loop back to VTK
|
||||
// ConnectionBlock blocker(d->m_UpdateSignal);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <vtkPiecewiseFunction.h>
|
||||
#include <vtkSmartVolumeMapper.h>
|
||||
#include <vtkVolumeProperty.h>
|
||||
#include <vtkMatrix4x4.h>
|
||||
|
||||
#include <vtkActor.h>
|
||||
#include <vtkPolyDataMapper.h>
|
||||
@@ -49,6 +50,7 @@
|
||||
#include <Math/VoxImage.h>
|
||||
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
#include "Vtk/Math/vtkDense.h"
|
||||
|
||||
#include <vtkAutoInit.h>
|
||||
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
|
||||
@@ -128,9 +130,15 @@ vtkVoxImage::vtkVoxImage(Content &content)
|
||||
m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()),
|
||||
m_OutlineActor(vtkActor::New()),
|
||||
m_Reader(NULL), m_Writer(NULL), writer_factor(1.E6),
|
||||
m_Window(40/1.E6), m_Level(20/1.E6), m_ShadingPreset(0) {
|
||||
m_Window(1.0), m_Level(0.5), m_ShadingPreset(0) {
|
||||
// Transfer functions
|
||||
m_ColorFun = vtkColorTransferFunction::New();
|
||||
m_OpacityFun = vtkPiecewiseFunction::New();
|
||||
m_UpdateConnection = Object::connect(&m_Content, &uLib::Object::Updated, this, &vtkVoxImage::Update);
|
||||
|
||||
GetContent();
|
||||
InstallPipe();
|
||||
RescaleShaderRange();
|
||||
ULIB_ACTIVATE_DISPLAY_PROPERTIES;
|
||||
}
|
||||
|
||||
@@ -140,6 +148,8 @@ vtkVoxImage::~vtkVoxImage() {
|
||||
m_Asm->Delete();
|
||||
m_Outline->Delete();
|
||||
m_OutlineActor->Delete();
|
||||
m_ColorFun->Delete();
|
||||
m_OpacityFun->Delete();
|
||||
}
|
||||
|
||||
vtkImageData *vtkVoxImage::GetImageData() {
|
||||
@@ -181,6 +191,7 @@ void vtkVoxImage::ReadFromVKTFile(const char *fname) {
|
||||
|
||||
m_Image->DeepCopy(vtkscale->GetOutput());
|
||||
SetContent();
|
||||
RescaleShaderRange();
|
||||
} else {
|
||||
std::cerr << "Error: file does not contain structured points\n";
|
||||
}
|
||||
@@ -200,115 +211,134 @@ void vtkVoxImage::ReadFromXMLFile(const char *fname) {
|
||||
|
||||
m_Image->DeepCopy(vtkscale->GetOutput());
|
||||
SetContent();
|
||||
RescaleShaderRange();
|
||||
}
|
||||
|
||||
void vtkVoxImage::setShadingPreset(int blendType) {
|
||||
m_ShadingPreset = blendType;
|
||||
vtkSmartVolumeMapper *mapper = (vtkSmartVolumeMapper *)m_Actor->GetMapper();
|
||||
if (!mapper) return;
|
||||
vtkVolumeProperty *property = m_Actor->GetProperty();
|
||||
|
||||
static vtkColorTransferFunction *colorFun = vtkColorTransferFunction::New();
|
||||
static vtkPiecewiseFunction *opacityFun = vtkPiecewiseFunction::New();
|
||||
|
||||
float window = m_Window;
|
||||
float level = m_Level;
|
||||
|
||||
property->SetColor(colorFun);
|
||||
property->SetScalarOpacity(opacityFun);
|
||||
property->SetColor(m_ColorFun);
|
||||
property->SetScalarOpacity(m_OpacityFun);
|
||||
property->SetInterpolationTypeToLinear();
|
||||
|
||||
if (blendType != 6) {
|
||||
colorFun->RemoveAllPoints();
|
||||
opacityFun->RemoveAllPoints();
|
||||
}
|
||||
m_ColorFun->RemoveAllPoints();
|
||||
m_OpacityFun->RemoveAllPoints();
|
||||
|
||||
switch (blendType) {
|
||||
case 0:
|
||||
colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0);
|
||||
opacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window,
|
||||
1.0);
|
||||
case 0: // MIP
|
||||
m_ColorFun->AddRGBPoint(level - 0.5 * window, 0, 0, 0);
|
||||
m_ColorFun->AddRGBPoint(level + 0.5 * window, 1, 1, 1);
|
||||
m_OpacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
mapper->SetBlendModeToMaximumIntensity();
|
||||
break;
|
||||
case 1:
|
||||
colorFun->AddRGBSegment(level - 0.5 * window, 0.0, 0.0, 0.0,
|
||||
level + 0.5 * window, 1.0, 1.0, 1.0);
|
||||
opacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window,
|
||||
1.0);
|
||||
case 1: // Composite
|
||||
m_ColorFun->AddRGBPoint(level - 0.5 * window, 0, 0, 0);
|
||||
m_ColorFun->AddRGBPoint(level + 0.5 * window, 1, 1, 1);
|
||||
m_OpacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
mapper->SetBlendModeToComposite();
|
||||
property->ShadeOff();
|
||||
break;
|
||||
case 2:
|
||||
colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0);
|
||||
opacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window,
|
||||
1.0);
|
||||
case 2: // Composite Shaded
|
||||
m_ColorFun->AddRGBPoint(level - 0.5 * window, 0, 0, 0);
|
||||
m_ColorFun->AddRGBPoint(level + 0.5 * window, 1, 1, 1);
|
||||
m_OpacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
mapper->SetBlendModeToComposite();
|
||||
property->ShadeOn();
|
||||
break;
|
||||
case 3:
|
||||
colorFun->AddRGBPoint(-3024, 0, 0, 0, 0.5, 0.0);
|
||||
colorFun->AddRGBPoint(-1000, .62, .36, .18, 0.5, 0.0);
|
||||
colorFun->AddRGBPoint(-500, .88, .60, .29, 0.33, 0.45);
|
||||
colorFun->AddRGBPoint(3071, .83, .66, 1, 0.5, 0.0);
|
||||
opacityFun->AddPoint(-3024, 0, 0.5, 0.0);
|
||||
opacityFun->AddPoint(-1000, 0, 0.5, 0.0);
|
||||
opacityFun->AddPoint(-500, 1.0, 0.33, 0.45);
|
||||
opacityFun->AddPoint(3071, 1.0, 0.5, 0.0);
|
||||
mapper->SetBlendModeToComposite();
|
||||
property->ShadeOn();
|
||||
property->SetAmbient(0.1);
|
||||
property->SetDiffuse(0.9);
|
||||
property->SetSpecular(0.2);
|
||||
property->SetSpecularPower(10.0);
|
||||
property->SetScalarOpacityUnitDistance(0.8919);
|
||||
break;
|
||||
case 4:
|
||||
colorFun->AddRGBPoint(0.0, 0, 0, 1); // Blue
|
||||
colorFun->AddRGBPoint(level, 0, 1, 0); // Green
|
||||
colorFun->AddRGBPoint(level + 0.5*window, 1, 1, 0); // Yellow
|
||||
colorFun->AddRGBPoint(level + window, 1, 0, 0); // Red
|
||||
opacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
case 3: // Rainbow MIP
|
||||
m_ColorFun->AddRGBPoint(level - 0.5 * window, 0, 0, 1);
|
||||
m_ColorFun->AddRGBPoint(level, 0, 1, 0);
|
||||
m_ColorFun->AddRGBPoint(level + 0.5 * window, 1, 1, 0);
|
||||
m_ColorFun->AddRGBPoint(level + window, 1, 0, 0);
|
||||
m_OpacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
mapper->SetBlendModeToMaximumIntensity();
|
||||
break;
|
||||
case 5:
|
||||
colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0);
|
||||
opacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
case 4: // Additive
|
||||
m_ColorFun->AddRGBPoint(level - 0.5 * window, 0, 0, 0);
|
||||
m_ColorFun->AddRGBPoint(level + 0.5 * window, 1, 1, 1);
|
||||
m_OpacityFun->AddSegment(level - 0.5 * window, 0.0, level + 0.5 * window, 1.0);
|
||||
mapper->SetBlendModeToAdditive();
|
||||
break;
|
||||
default:
|
||||
vtkGenericWarningMacro("Unknown blend type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void vtkVoxImage::RescaleShaderRange() {
|
||||
double range[2];
|
||||
m_Image->GetScalarRange(range);
|
||||
m_Level = (range[0] + range[1]) / 2.0;
|
||||
m_Window = range[1] - range[0];
|
||||
if (m_Window <= 1e-9)
|
||||
m_Window = 1.0;
|
||||
setShadingPreset(m_ShadingPreset);
|
||||
}
|
||||
|
||||
void vtkVoxImage::SetRepresentation(Representation mode) {
|
||||
Puppet::SetRepresentation(mode); // Ensure base class data state is updated
|
||||
|
||||
if (mode == Wireframe) {
|
||||
m_Actor->SetVisibility(0);
|
||||
m_OutlineActor->SetVisibility(1);
|
||||
} else if (mode == Surface) {
|
||||
m_OutlineActor->GetProperty()->SetRepresentationToWireframe();
|
||||
} else if (mode == Volume) {
|
||||
m_Actor->SetVisibility(1);
|
||||
m_OutlineActor->SetVisibility(1); // Keep outline visible as boundary
|
||||
m_OutlineActor->SetVisibility(1);
|
||||
m_OutlineActor->GetProperty()->SetRepresentationToWireframe();
|
||||
} else {
|
||||
Puppet::SetRepresentation(mode);
|
||||
// Other representations (Points, Surface, etc) are handled by basic Puppet
|
||||
// behavior which affects the m_Asm parts.
|
||||
}
|
||||
}
|
||||
|
||||
void vtkVoxImage::serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version) {
|
||||
// Call base class if it has display properties
|
||||
Puppet::serialize_display(ar, version);
|
||||
// Call base class to show Transform and Appearance properties
|
||||
// Puppet::serialize_display(ar, version);
|
||||
|
||||
// Use the member variables if they are available
|
||||
// Use the member variables for volume rendering parameters
|
||||
ar & boost::serialization::make_hrp("Window", m_Window);
|
||||
ar & boost::serialization::make_hrp("Level", m_Level);
|
||||
ar & boost::serialization::make_hrp_enum("Shading", m_ShadingPreset, {"MIP", "Composite", "Composite Shaded", "MIP Bone", "MIP Hot", "Additive"});
|
||||
ar & boost::serialization::make_hrp_enum("Shading", m_ShadingPreset,
|
||||
{"MIP", "Composite", "Composite Shaded", "MIP Bone", "MIP Hot", "Additive"});
|
||||
}
|
||||
|
||||
void vtkVoxImage::SyncFromVtk() {
|
||||
if (auto *root = this->GetProxyProp()) {
|
||||
vtkMatrix4x4 *rootMat = root->GetUserMatrix();
|
||||
if (rootMat) {
|
||||
Matrix4f vtkLocal = VtkToMatrix4f(rootMat);
|
||||
// Synchronize TRS from VTK, compensating for local volume offset
|
||||
m_Content.FromMatrix(vtkLocal); // * m_Content.GetLocalMatrix().inverse());
|
||||
m_Content.Updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vtkVoxImage::Update() {
|
||||
if (auto *root = vtkProp3D::SafeDownCast(this->GetProp())) {
|
||||
vtkNew<vtkMatrix4x4> m;
|
||||
Matrix4fToVtk(m_Content.GetMatrix(), m); // * m_Content.GetLocalMatrix(), m);
|
||||
root->SetUserMatrix(m);
|
||||
root->Modified();
|
||||
// std::cout << "[vtkVoxImage::Update] Set Proxy UserMatrix:" << std::endl;
|
||||
// std::cout << m_Content.GetMatrix() << std::endl;
|
||||
}
|
||||
setShadingPreset(m_ShadingPreset);
|
||||
m_Actor->Update();
|
||||
m_Outline->SetBounds(m_Image->GetBounds());
|
||||
m_Outline->Update();
|
||||
|
||||
ConnectionBlock blocker(m_UpdateConnection);
|
||||
this->Puppet::Update();
|
||||
}
|
||||
|
||||
|
||||
void vtkVoxImage::InstallPipe() {
|
||||
vtkSmartPointer<vtkSmartVolumeMapper> mapper =
|
||||
vtkSmartPointer<vtkSmartVolumeMapper>::New();
|
||||
@@ -320,7 +350,7 @@ void vtkVoxImage::InstallPipe() {
|
||||
mapper->Update();
|
||||
|
||||
m_Actor->SetMapper(mapper);
|
||||
this->setShadingPreset(0);
|
||||
this->setShadingPreset(m_ShadingPreset);
|
||||
mapper->Update();
|
||||
|
||||
m_Outline->SetBounds(m_Image->GetBounds());
|
||||
@@ -331,13 +361,13 @@ void vtkVoxImage::InstallPipe() {
|
||||
m_OutlineActor->SetMapper(mmapper);
|
||||
m_OutlineActor->GetProperty()->SetRepresentationToWireframe();
|
||||
m_OutlineActor->GetProperty()->SetAmbient(0.7);
|
||||
|
||||
|
||||
m_Asm->AddPart(m_Actor);
|
||||
m_Asm->AddPart(m_OutlineActor);
|
||||
this->SetProp(m_Asm);
|
||||
|
||||
// Default look
|
||||
this->SetRepresentation(Surface);
|
||||
this->SetRepresentation(Volume);
|
||||
}
|
||||
|
||||
} // namespace Vtk
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
class vtkImageData;
|
||||
class vtkActor;
|
||||
class vtkColorTransferFunction;
|
||||
class vtkPiecewiseFunction;
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
@@ -55,6 +57,8 @@ public:
|
||||
|
||||
void SetContent();
|
||||
|
||||
vtkProp3D *GetProp() override { return m_Asm; }
|
||||
|
||||
vtkImageData *GetImageData();
|
||||
|
||||
void SaveToXMLFile(const char *fname);
|
||||
@@ -65,8 +69,10 @@ public:
|
||||
|
||||
void setShadingPreset(int blendType = 2);
|
||||
void SetRepresentation(Representation mode);
|
||||
void RescaleShaderRange();
|
||||
|
||||
void Update() override;
|
||||
void SyncFromVtk() override;
|
||||
void serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version = 0) override;
|
||||
|
||||
protected:
|
||||
@@ -88,6 +94,11 @@ private:
|
||||
float m_Window;
|
||||
float m_Level;
|
||||
int m_ShadingPreset;
|
||||
|
||||
Connection m_UpdateConnection;
|
||||
|
||||
class vtkColorTransferFunction *m_ColorFun;
|
||||
class vtkPiecewiseFunction *m_OpacityFun;
|
||||
};
|
||||
|
||||
} // namespace Vtk
|
||||
|
||||
@@ -4,6 +4,7 @@ set(TESTS
|
||||
vtkHandlerWidget
|
||||
PuppetPropertyTest
|
||||
PuppetParentingTest
|
||||
vtkQViewportTest
|
||||
# vtkVoxImageTest
|
||||
# vtkTriangleMeshTest
|
||||
)
|
||||
|
||||
87
src/Vtk/testing/vtkQViewportTest.cpp
Normal file
87
src/Vtk/testing/vtkQViewportTest.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*//////////////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
#include <QtGlobal>
|
||||
#include <Vtk/vtkQViewport.h>
|
||||
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkCubeSource.h>
|
||||
#include <vtkPolyDataMapper.h>
|
||||
#include <vtkActor.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkRenderer.h>
|
||||
|
||||
#include "testing-prototype.h"
|
||||
|
||||
using namespace uLib;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Force X11 on Linux to avoid Wayland connection issues in headless/X11 environments
|
||||
#if defined(Q_OS_LINUX)
|
||||
qputenv("QT_QPA_PLATFORM", "xcb");
|
||||
#endif
|
||||
|
||||
BEGIN_TESTING(vtk QViewport Test);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
app.processEvents();
|
||||
|
||||
Vtk::QViewport viewport;
|
||||
viewport.resize(800, 600);
|
||||
viewport.show();
|
||||
|
||||
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
|
||||
cube->SetXLength(10);
|
||||
cube->SetYLength(10);
|
||||
cube->SetZLength(10);
|
||||
cube->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputConnection(cube->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->SetMapper(mapper);
|
||||
actor->GetProperty()->SetColor(1, 0, 0);
|
||||
|
||||
viewport.addProp(actor);
|
||||
viewport.Render();
|
||||
|
||||
ASSERT_NOT_NULL(viewport.GetRenderWindow());
|
||||
ASSERT_NOT_NULL(viewport.GetRenderer());
|
||||
|
||||
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
|
||||
// Run application for a while to see the result
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
END_TESTING;
|
||||
}
|
||||
@@ -134,11 +134,11 @@ public:
|
||||
|
||||
vtkActor *actor = vtkActor::SafeDownCast(p);
|
||||
if (actor) {
|
||||
if (m_Representation != -1) {
|
||||
if (m_Representation != -1 && m_Representation != Puppet::Volume) {
|
||||
if (m_Representation == Puppet::SurfaceWithEdges) {
|
||||
actor->GetProperty()->SetRepresentation(VTK_SURFACE);
|
||||
actor->GetProperty()->SetEdgeVisibility(1);
|
||||
} else {
|
||||
} else if (m_Representation != Puppet::Outline && m_Representation != Puppet::Slice) {
|
||||
actor->GetProperty()->SetRepresentation(m_Representation);
|
||||
actor->GetProperty()->SetEdgeVisibility(0);
|
||||
}
|
||||
@@ -628,6 +628,8 @@ struct AppearanceProxy {
|
||||
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);
|
||||
ar & boost::serialization::make_hrp("ShowBoundingBox", pd->m_ShowBoundingBox);
|
||||
ar & boost::serialization::make_hrp("ShowScaleMeasures", pd->m_ShowScaleMeasures);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ struct ViewerData {
|
||||
vtkRenderWindow *m_RenderWindow;
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> m_Interactor;
|
||||
vtkSmartPointer<vtkButtonWidget> m_GridButton;
|
||||
vtkSmartPointer<vtkButtonWidget> m_ProjButton;
|
||||
|
||||
ViewerData() : m_RenderWindow(vtkRenderWindow::New()) {}
|
||||
~ViewerData() {
|
||||
@@ -97,6 +98,11 @@ Viewer::~Viewer() {
|
||||
dv->m_GridButton->SetInteractor(nullptr);
|
||||
dv->m_GridButton = nullptr;
|
||||
}
|
||||
if (dv->m_ProjButton) {
|
||||
dv->m_ProjButton->Off();
|
||||
dv->m_ProjButton->SetInteractor(nullptr);
|
||||
dv->m_ProjButton = nullptr;
|
||||
}
|
||||
if (this->GetRenderWindow()) {
|
||||
this->GetRenderWindow()->RemoveAllObservers();
|
||||
}
|
||||
@@ -123,6 +129,7 @@ void Viewer::InstallPipe() {
|
||||
// Setup native grid button
|
||||
if (!std::getenv("CTEST_PROJECT_NAME")) {
|
||||
SetupGridButton();
|
||||
SetupProjButton();
|
||||
}
|
||||
|
||||
// BUT we want to override the style with our custom NoSpin version
|
||||
@@ -238,9 +245,91 @@ void Viewer::UpdateGridButtonPosition() {
|
||||
rep->PlaceWidget(bds);
|
||||
}
|
||||
|
||||
void Viewer::Start() {
|
||||
void Viewer::SetupProjButton() {
|
||||
if (!dv->m_RenderWindow || !dv->m_RenderWindow->GetInteractor()) return;
|
||||
|
||||
vtkNew<vtkImageCanvasSource2D> canvas;
|
||||
canvas->SetScalarTypeToUnsignedChar();
|
||||
canvas->SetNumberOfScalarComponents(4);
|
||||
canvas->SetExtent(0, 63, 0, 63, 0, 0);
|
||||
|
||||
// State 0: Perspective (gray trapezoid-like lines)
|
||||
canvas->SetDrawColor(0, 0, 0, 0);
|
||||
canvas->FillBox(0, 63, 0, 63);
|
||||
canvas->SetDrawColor(120, 120, 120, 255);
|
||||
canvas->DrawSegment(16, 16, 48, 16);
|
||||
canvas->DrawSegment(48, 16, 56, 48);
|
||||
canvas->DrawSegment(56, 48, 8, 48);
|
||||
canvas->DrawSegment(8, 48, 16, 16);
|
||||
canvas->Update();
|
||||
|
||||
vtkNew<vtkImageData> imgPersp;
|
||||
imgPersp->DeepCopy(canvas->GetOutput());
|
||||
|
||||
// State 1: Orthographic (white rectangle)
|
||||
canvas->SetDrawColor(0, 0, 0, 0);
|
||||
canvas->FillBox(0, 63, 0, 63);
|
||||
canvas->SetDrawColor(255, 255, 255, 255);
|
||||
canvas->DrawSegment(12, 16, 52, 16);
|
||||
canvas->DrawSegment(52, 16, 52, 48);
|
||||
canvas->DrawSegment(52, 48, 12, 48);
|
||||
canvas->DrawSegment(12, 48, 12, 16);
|
||||
canvas->Update();
|
||||
|
||||
vtkNew<vtkImageData> imgOrtho;
|
||||
imgOrtho->DeepCopy(canvas->GetOutput());
|
||||
|
||||
vtkNew<vtkTexturedButtonRepresentation2D> rep;
|
||||
rep->SetNumberOfStates(2);
|
||||
rep->SetButtonTexture(0, imgPersp);
|
||||
rep->SetButtonTexture(1, imgOrtho);
|
||||
|
||||
dv->m_ProjButton = vtkSmartPointer<vtkButtonWidget>::New();
|
||||
dv->m_ProjButton->SetInteractor(dv->m_RenderWindow->GetInteractor());
|
||||
dv->m_ProjButton->SetRepresentation(rep);
|
||||
|
||||
UpdateProjButtonPosition();
|
||||
|
||||
vtkNew<vtkCallbackCommand> resizeCallback;
|
||||
resizeCallback->SetClientData(this);
|
||||
resizeCallback->SetCallback([](vtkObject*, unsigned long, void* clientdata, void*){
|
||||
static_cast<Viewer*>(clientdata)->UpdateProjButtonPosition();
|
||||
});
|
||||
dv->m_RenderWindow->AddObserver(vtkCommand::ModifiedEvent, resizeCallback);
|
||||
|
||||
vtkNew<vtkCallbackCommand> stateCallback;
|
||||
stateCallback->SetClientData(this);
|
||||
stateCallback->SetCallback([](vtkObject* caller, unsigned long, void* clientdata, void*){
|
||||
auto* btn = vtkButtonWidget::SafeDownCast(caller);
|
||||
auto* v = static_cast<Viewer*>(clientdata);
|
||||
auto* r = vtkTexturedButtonRepresentation2D::SafeDownCast(btn->GetRepresentation());
|
||||
v->SetParallelProjection(r->GetState() == 1);
|
||||
});
|
||||
dv->m_ProjButton->AddObserver(vtkCommand::StateChangedEvent, stateCallback);
|
||||
dv->m_ProjButton->On();
|
||||
|
||||
rep->SetState(GetParallelProjection() ? 1 : 0);
|
||||
}
|
||||
|
||||
void Viewer::UpdateProjButtonPosition() {
|
||||
if (!dv->m_ProjButton || !dv->m_RenderWindow) return;
|
||||
auto* rep = vtkTexturedButtonRepresentation2D::SafeDownCast(dv->m_ProjButton->GetRepresentation());
|
||||
if (!rep) return;
|
||||
|
||||
int *sz = dv->m_RenderWindow->GetSize();
|
||||
if (sz[0] == 0 || sz[1] == 0) return;
|
||||
|
||||
int margin_right = 23;
|
||||
int margin_top = 220; // below the grid button (170 + 50)
|
||||
int btnSz = 100;
|
||||
double bds[6] = { (double)sz[0] - btnSz - margin_right, (double)sz[0] - margin_right,
|
||||
(double)sz[1] - margin_top - btnSz/2.0, (double)sz[1] - margin_top + btnSz/2.0, 0, 0 };
|
||||
rep->PlaceWidget(bds);
|
||||
}
|
||||
|
||||
void Viewer::Start() {
|
||||
if (std::getenv("CTEST_PROJECT_NAME")) return;
|
||||
dv->m_RenderWindow->GetInteractor()->Start();
|
||||
dv->m_RenderWindow->GetInteractor()->Start();
|
||||
}
|
||||
|
||||
vtkRenderWindow *Viewer::GetRenderWindow() { return dv->m_RenderWindow; }
|
||||
|
||||
@@ -38,6 +38,9 @@ private:
|
||||
void SetupGridButton();
|
||||
void UpdateGridButtonPosition();
|
||||
|
||||
void SetupProjButton();
|
||||
void UpdateProjButtonPosition();
|
||||
|
||||
struct ViewerData *dv;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include "Vtk/Math/vtkCylinder.h"
|
||||
#include "Vtk/Math/vtkAssembly.h"
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
|
||||
#include "HEP/Detectors/vtkDetectorChamber.h"
|
||||
#include "HEP/Geant/vtkBoxSolid.h"
|
||||
|
||||
#include <vtkAssembly.h>
|
||||
#include <vtkPropCollection.h>
|
||||
@@ -116,16 +118,18 @@ void vtkObjectsContext::SyncFromVtk() {
|
||||
Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
|
||||
if (!obj) return nullptr;
|
||||
|
||||
if (auto* box = dynamic_cast<uLib::ContainerBox*>(obj)) {
|
||||
if (auto* vox = dynamic_cast<uLib::Abstract::VoxImage*>(obj)) {
|
||||
return new vtkVoxImage(*vox);
|
||||
} else if (auto* box = dynamic_cast<uLib::ContainerBox*>(obj)) {
|
||||
return new vtkContainerBox(box);
|
||||
} else if (auto* chamber = dynamic_cast<uLib::DetectorChamber*>(obj)) {
|
||||
return new vtkDetectorChamber(chamber);
|
||||
} else if (auto* cylinder = dynamic_cast<uLib::Cylinder*>(obj)) {
|
||||
return new vtkCylinder(cylinder);
|
||||
} else if (auto* vox = dynamic_cast<uLib::Abstract::VoxImage*>(obj)) {
|
||||
return new vtkVoxImage(*vox);
|
||||
} else if (auto* assembly = dynamic_cast<uLib::Assembly*>(obj)) {
|
||||
return new Assembly(assembly);
|
||||
} else if (auto* box = dynamic_cast<uLib::Geant::BoxSolid*>(obj)) {
|
||||
return new vtkBoxSolid(box);
|
||||
}
|
||||
|
||||
// Fallback if we don't know the exact class but it might be a context itself
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Vtk {
|
||||
*/
|
||||
class vtkObjectsContext : public Puppet {
|
||||
public:
|
||||
virtual const char* GetClassName() const override { return "vtkObjectsContext"; }
|
||||
uLibTypeMacro(vtkObjectsContext, Puppet)
|
||||
vtkObjectsContext(uLib::ObjectsContext *context);
|
||||
virtual ~vtkObjectsContext();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ QViewport::QViewport(QWidget* parent)
|
||||
, Viewport()
|
||||
, m_VtkWidget(nullptr)
|
||||
, m_GridButton(nullptr)
|
||||
, m_ProjButton(nullptr)
|
||||
{
|
||||
// Build the layout – zero margins so VTK fills the entire widget
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
@@ -58,6 +59,36 @@ QViewport::QViewport(QWidget* parent)
|
||||
m_GridButton->setChecked(true); // Grid is on by default
|
||||
connect(m_GridButton, &QPushButton::clicked, this, &QViewport::onGridButtonClicked);
|
||||
|
||||
// Projection Toggle Button (below grid button)
|
||||
m_ProjButton = new QPushButton(m_VtkWidget);
|
||||
m_ProjButton->setText("P");
|
||||
m_ProjButton->setFixedSize(40, 40);
|
||||
m_ProjButton->setToolTip("Toggle Perspective / Orthographic");
|
||||
m_ProjButton->setStyleSheet(
|
||||
"QPushButton {"
|
||||
" border-radius: 20px;"
|
||||
" background-color: rgba(40, 40, 40, 180);"
|
||||
" color: white;"
|
||||
" font-size: 22px;"
|
||||
" border: 1.5px solid rgba(255, 255, 255, 60);"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
" background-color: rgba(70, 70, 70, 200);"
|
||||
" border: 1.5px solid rgba(255, 255, 255, 100);"
|
||||
"}"
|
||||
"QPushButton:checked {"
|
||||
" background-color: rgba(0, 120, 215, 200);"
|
||||
" color: white;"
|
||||
" border: 1.5px solid rgba(255, 255, 255, 120);"
|
||||
"}"
|
||||
"QPushButton:pressed {"
|
||||
" background-color: rgba(0, 90, 160, 220);"
|
||||
"}"
|
||||
);
|
||||
m_ProjButton->setCheckable(true);
|
||||
m_ProjButton->setChecked(false); // Perspective by default
|
||||
connect(m_ProjButton, &QPushButton::clicked, this, &QViewport::onProjButtonClicked);
|
||||
|
||||
// After the Qt widget exists but before the first paint,
|
||||
// attach the renderer and configure the pipeline.
|
||||
SetupPipeline();
|
||||
@@ -81,7 +112,6 @@ void QViewport::SetupPipeline()
|
||||
|
||||
void QViewport::Render()
|
||||
{
|
||||
UpdateGrid();
|
||||
if (m_VtkWidget && m_VtkWidget->renderWindow())
|
||||
m_VtkWidget->renderWindow()->Render();
|
||||
}
|
||||
@@ -101,6 +131,11 @@ void QViewport::onGridButtonClicked()
|
||||
SetGridVisible(m_GridButton->isChecked());
|
||||
}
|
||||
|
||||
void QViewport::onProjButtonClicked()
|
||||
{
|
||||
SetParallelProjection(m_ProjButton->isChecked());
|
||||
}
|
||||
|
||||
void QViewport::OnSelectionChanged(Puppet* p)
|
||||
{
|
||||
emit puppetSelected(p);
|
||||
@@ -113,9 +148,14 @@ void QViewport::resizeEvent(QResizeEvent* event)
|
||||
// Position under the gizmo (top-right corner).
|
||||
// Standard CameraOrientationWidget is usually 150-180px.
|
||||
int x = width() - m_GridButton->width() - 10;
|
||||
int y = 160;
|
||||
int y = 160;
|
||||
m_GridButton->move(x, y);
|
||||
}
|
||||
if (m_ProjButton) {
|
||||
int x = width() - m_ProjButton->width() - 10;
|
||||
int y = 210;
|
||||
m_ProjButton->move(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vtk
|
||||
|
||||
@@ -51,12 +51,14 @@ protected:
|
||||
|
||||
private slots:
|
||||
void onGridButtonClicked();
|
||||
void onProjButtonClicked();
|
||||
|
||||
private:
|
||||
void SetupPipeline();
|
||||
|
||||
QVTKOpenGLNativeWidget* m_VtkWidget;
|
||||
QPushButton* m_GridButton;
|
||||
QPushButton* m_ProjButton;
|
||||
};
|
||||
|
||||
} // namespace Vtk
|
||||
|
||||
@@ -537,6 +537,21 @@ bool Viewport::GetGridVisible() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Viewport::SetParallelProjection(bool parallel)
|
||||
{
|
||||
if (pv->m_Renderer && pv->m_Renderer->GetActiveCamera()) {
|
||||
pv->m_Renderer->GetActiveCamera()->SetParallelProjection(parallel ? 1 : 0);
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
bool Viewport::GetParallelProjection() const
|
||||
{
|
||||
if (pv->m_Renderer && pv->m_Renderer->GetActiveCamera())
|
||||
return pv->m_Renderer->GetActiveCamera()->GetParallelProjection() != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Viewport::SetGridAxis(Axis axis)
|
||||
{
|
||||
m_GridAxis = axis;
|
||||
|
||||
@@ -73,6 +73,10 @@ public:
|
||||
void SetGridAxis(Axis axis);
|
||||
Axis GetGridAxis() const { return m_GridAxis; }
|
||||
|
||||
// Projection control
|
||||
void SetParallelProjection(bool parallel);
|
||||
bool GetParallelProjection() const;
|
||||
|
||||
protected:
|
||||
void SetupPipeline(vtkRenderWindowInteractor* iren);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user