Compare commits
4 Commits
7d72f825ae
...
andrea-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e09a614fa5 | ||
|
|
7f6323403d | ||
|
|
a53b3051de | ||
|
|
c53570192f |
@@ -10,7 +10,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
export MAMBA_EXE="/home/share/micromamba/bin/micromamba"
|
export MAMBA_EXE="/home/share/micromamba/bin/micromamba"
|
||||||
export MAMBA_ROOT_PREFIX="/home/share/micromamba"
|
export MAMBA_ROOT_PREFIX="/home/share/micromamba"
|
||||||
eval "$(/home/share/micromamba/bin/micromamba shell hook --shell bash)"
|
eval "$(/home/share/micromamba/bin/micromamba shell hook --shell bash)"
|
||||||
micromamba activate uLib
|
micromamba activate mutom
|
||||||
|
|
||||||
# Configure (from repo root, using Conan preset — uses Ninja + ccache)
|
# Configure (from repo root, using Conan preset — uses Ninja + ccache)
|
||||||
cmake --preset conan-release
|
cmake --preset conan-release
|
||||||
|
|||||||
@@ -15,20 +15,11 @@ if(POLICY CMP0167)
|
|||||||
cmake_policy(SET CMP0167 NEW)
|
cmake_policy(SET CMP0167 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
## -------------------------------------------------------------------------- ##
|
## -------------------------------------------------------------------------- ##
|
||||||
|
|
||||||
project(uLib)
|
project(uLib)
|
||||||
|
|
||||||
# Remove GCC-only flag injected by conda's CFLAGS/CXXFLAGS that clang doesn't support.
|
|
||||||
# Must run after project() since that's when CMake initialises CMAKE_<LANG>_FLAGS from env.
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
||||||
foreach(_lang C CXX)
|
|
||||||
foreach(_var CMAKE_${_lang}_FLAGS CMAKE_${_lang}_FLAGS_RELEASE CMAKE_${_lang}_FLAGS_RELWITHDEBINFO CMAKE_${_lang}_FLAGS_DEBUG)
|
|
||||||
string(REPLACE "-fno-merge-constants" "" ${_var} "${${_var}}")
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
# CUDA Toolkit seems to be missing locally. Toggle ON if nvcc is made available.
|
||||||
option(USE_CUDA "Enable CUDA support" OFF)
|
option(USE_CUDA "Enable CUDA support" OFF)
|
||||||
if(USE_CUDA)
|
if(USE_CUDA)
|
||||||
@@ -133,8 +124,6 @@ find_package(Eigen3 CONFIG REQUIRED)
|
|||||||
get_target_property(EIGEN3_INCLUDE_DIRS Eigen3::Eigen INTERFACE_INCLUDE_DIRECTORIES)
|
get_target_property(EIGEN3_INCLUDE_DIRS Eigen3::Eigen INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
include_directories(${EIGEN3_INCLUDE_DIRS})
|
include_directories(${EIGEN3_INCLUDE_DIRS})
|
||||||
|
|
||||||
find_package(OpenMP)
|
|
||||||
|
|
||||||
find_package(ROOT CONFIG REQUIRED)
|
find_package(ROOT CONFIG REQUIRED)
|
||||||
include(${ROOT_USE_FILE})
|
include(${ROOT_USE_FILE})
|
||||||
|
|
||||||
@@ -156,8 +145,6 @@ else()
|
|||||||
IOXML
|
IOXML
|
||||||
IOXMLParser
|
IOXMLParser
|
||||||
ImagingCore
|
ImagingCore
|
||||||
ImagingHybrid
|
|
||||||
ImagingSources
|
|
||||||
InteractionStyle
|
InteractionStyle
|
||||||
InteractionWidgets
|
InteractionWidgets
|
||||||
RenderingAnnotation
|
RenderingAnnotation
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -30,13 +30,13 @@ You can create and activate the environment using either `micromamba` or `conda`
|
|||||||
**Using Micromamba:**
|
**Using Micromamba:**
|
||||||
```bash
|
```bash
|
||||||
micromamba env create -f condaenv.yml
|
micromamba env create -f condaenv.yml
|
||||||
micromamba activate uLib
|
micromamba activate mutom
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using Conda:**
|
**Using Conda:**
|
||||||
```bash
|
```bash
|
||||||
conda env create -f condaenv.yml
|
conda env create -f condaenv.yml
|
||||||
conda activate uLib
|
conda activate mutom
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configure and Build
|
### Configure and Build
|
||||||
@@ -65,24 +65,12 @@ cmake --preset conan-release
|
|||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Clean build (wipe and rebuild everything):**
|
|
||||||
```bash
|
|
||||||
cmake --build build --clean-first -j$(nproc)
|
|
||||||
```
|
|
||||||
|
|
||||||
6. **Run tests:**
|
|
||||||
```bash
|
|
||||||
cmake --build build --target test -j$(nproc)
|
|
||||||
# or equivalently:
|
|
||||||
ctest --test-dir build --output-on-failure -j$(nproc)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### LLVM/Clang build (clang + lld + ccache — fastest)
|
#### LLVM/Clang build (clang + lld + ccache — fastest)
|
||||||
|
|
||||||
A `fast` conan profile is provided that uses **clang**, **lld** (LLVM linker), and **ccache**. Install them into your environment first:
|
A `fast` conan profile is provided that uses **clang**, **lld** (LLVM linker), and **ccache**. Install them into your environment first:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
micromamba install -n uLib -y clang clangxx lld -c conda-forge
|
micromamba install -n mutom -y clang clangxx lld -c conda-forge
|
||||||
```
|
```
|
||||||
|
|
||||||
Then build using the `fast` profile:
|
Then build using the `fast` profile:
|
||||||
@@ -103,6 +91,6 @@ The `fast` profile is defined at `~/.conan2/profiles/fast` and sets:
|
|||||||
### Make python package
|
### Make python package
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
micromamba run -n uLib env USE_CUDA=ON poetry install
|
micromamba run -n mutom env USE_CUDA=ON poetry install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[requires]
|
[requires]
|
||||||
eigen/3.4.0
|
eigen/3.4.0
|
||||||
boost/1.86.0
|
boost/1.83.0
|
||||||
# pybind11/3.0.2
|
# pybind11/3.0.2
|
||||||
hdf5/1.14.3
|
hdf5/1.14.3
|
||||||
|
|
||||||
|
|||||||
13
condaenv.yml
13
condaenv.yml
@@ -1,4 +1,4 @@
|
|||||||
name: uLib
|
name: mutom
|
||||||
channels:
|
channels:
|
||||||
- conda-forge
|
- conda-forge
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -7,13 +7,4 @@ dependencies:
|
|||||||
- cmake
|
- cmake
|
||||||
- conan
|
- conan
|
||||||
- root
|
- root
|
||||||
- vtk=9.4 # VTK 9.4
|
- vtk
|
||||||
- pybind11
|
|
||||||
# - boost=1.86.0 # requested by VTK 9.4
|
|
||||||
- ninja
|
|
||||||
- clang
|
|
||||||
- clangxx
|
|
||||||
- lld
|
|
||||||
- ccache
|
|
||||||
- OpenMP
|
|
||||||
- Geant4
|
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ template <class ArchiveImplementation> class polymorphic_iarchive_route;
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace serialization {
|
namespace serialization {
|
||||||
template <typename T> struct hrp;
|
template <typename T> struct hrp;
|
||||||
template <typename T> struct hrp_val;
|
|
||||||
template <typename T> struct hrp_enum;
|
|
||||||
template <typename T> struct hrp_enum_val;
|
|
||||||
}
|
}
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
@@ -180,24 +177,6 @@ public:
|
|||||||
return *this->This();
|
return *this->This();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator>>(const boost::serialization::hrp_val<T> &t) {
|
|
||||||
this->This()->load_override(const_cast<boost::serialization::hrp_val<T> &>(t));
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator>>(const boost::serialization::hrp_enum<T> &t) {
|
|
||||||
this->This()->load_override(const_cast<boost::serialization::hrp_enum<T> &>(t));
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator>>(const boost::serialization::hrp_enum_val<T> &t) {
|
|
||||||
this->This()->load_override(const_cast<boost::serialization::hrp_enum_val<T> &>(t));
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the & operator
|
// the & operator
|
||||||
template <class T> Archive &operator&(T &t) { return *(this->This()) >> t; }
|
template <class T> Archive &operator&(T &t) { return *(this->This()) >> t; }
|
||||||
|
|
||||||
@@ -211,21 +190,6 @@ public:
|
|||||||
return *(this->This()) >> t;
|
return *(this->This()) >> t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_val<T> &t) {
|
|
||||||
return *(this->This()) >> t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_enum<T> &t) {
|
|
||||||
return *(this->This()) >> t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_enum_val<T> &t) {
|
|
||||||
return *(this->This()) >> t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the == operator
|
// the == operator
|
||||||
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
|
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
|
||||||
|
|
||||||
@@ -266,61 +230,11 @@ public:
|
|||||||
return *this->This();
|
return *this->This();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> Archive &operator<<(const boost::serialization::hrp<T> &t) {
|
|
||||||
this->This()->save_override(t);
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> Archive &operator<<(const boost::serialization::hrp_val<T> &t) {
|
|
||||||
this->This()->save_override(t);
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> Archive &operator<<(const boost::serialization::hrp_enum<T> &t) {
|
|
||||||
this->This()->save_override(t);
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> Archive &operator<<(const boost::serialization::hrp_enum_val<T> &t) {
|
|
||||||
this->This()->save_override(t);
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> Archive &operator<<(const boost::serialization::nvp<T> &t) {
|
|
||||||
this->This()->save_override(t);
|
|
||||||
return *this->This();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the & operator
|
// the & operator
|
||||||
template <class T> Archive &operator&(const T &t) {
|
template <class T> Archive &operator&(const T &t) {
|
||||||
return *this->This() << t;
|
return *this->This() << t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp<T> &t) {
|
|
||||||
return *this->This() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_val<T> &t) {
|
|
||||||
return *this->This() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_enum<T> &t) {
|
|
||||||
return *this->This() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::hrp_enum_val<T> &t) {
|
|
||||||
return *this->This() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Archive &operator&(const boost::serialization::nvp<T> &t) {
|
|
||||||
return *this->This() << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the == operator
|
// the == operator
|
||||||
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
|
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ set(HEADERS
|
|||||||
StringReader.h
|
StringReader.h
|
||||||
Threads.h
|
Threads.h
|
||||||
Monitor.h
|
Monitor.h
|
||||||
Property.h
|
|
||||||
Types.h
|
Types.h
|
||||||
Uuid.h
|
Uuid.h
|
||||||
Vector.h
|
Vector.h
|
||||||
|
|||||||
@@ -65,19 +65,10 @@ public:
|
|||||||
std::vector<Slot> slov;
|
std::vector<Slot> slov;
|
||||||
std::vector<PropertyBase*> m_Properties;
|
std::vector<PropertyBase*> m_Properties;
|
||||||
std::vector<PropertyBase*> m_DynamicProperties;
|
std::vector<PropertyBase*> m_DynamicProperties;
|
||||||
std::vector<PropertyBase*> m_DisplayProperties;
|
|
||||||
bool m_SignalsBlocked;
|
bool m_SignalsBlocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementations of Property methods
|
// Implementations of Property methods
|
||||||
void Object::RegisterDisplayProperty(PropertyBase* prop) {
|
|
||||||
if (prop) d->m_DisplayProperties.push_back(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<PropertyBase*>& Object::GetDisplayProperties() const {
|
|
||||||
return d->m_DisplayProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::RegisterProperty(PropertyBase* prop) {
|
void Object::RegisterProperty(PropertyBase* prop) {
|
||||||
if (prop) {
|
if (prop) {
|
||||||
d->m_Properties.push_back(prop);
|
d->m_Properties.push_back(prop);
|
||||||
@@ -113,9 +104,24 @@ void Object::NotifyPropertiesUpdated() {
|
|||||||
for (auto* p : d->m_DynamicProperties) p->Updated();
|
for (auto* p : d->m_DynamicProperties) p->Updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In Object.h, the template serialize needs to be updated to call property serialization.
|
||||||
|
// However, since Object::serialize is a template in the header, we might need a helper here.
|
||||||
|
|
||||||
|
template <class ArchiveT>
|
||||||
|
void Object::serialize(ArchiveT &ar, const unsigned int version) {
|
||||||
|
ar & boost::serialization::make_nvp("InstanceName", d->m_InstanceName);
|
||||||
|
for (auto* prop : d->m_Properties) {
|
||||||
|
prop->serialize(ar, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Object::Updated() { ULIB_SIGNAL_EMIT(Object::Updated); }
|
void Object::Updated() { ULIB_SIGNAL_EMIT(Object::Updated); }
|
||||||
void Object::PropertyUpdated() { ULIB_SIGNAL_EMIT(Object::PropertyUpdated); }
|
void Object::PropertyUpdated() { ULIB_SIGNAL_EMIT(Object::PropertyUpdated); }
|
||||||
|
|
||||||
|
template <class ArchiveT>
|
||||||
|
void Object::save_override(ArchiveT &ar, const unsigned int version) {}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -92,11 +92,9 @@ public:
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// PROPERTIES //
|
// PROPERTIES //
|
||||||
virtual void RegisterProperty(PropertyBase* property);
|
void RegisterProperty(PropertyBase* prop);
|
||||||
virtual void RegisterDynamicProperty(PropertyBase* property);
|
void RegisterDynamicProperty(PropertyBase* prop);
|
||||||
virtual void RegisterDisplayProperty(PropertyBase* property);
|
const std::vector<PropertyBase*>& GetProperties() const;
|
||||||
virtual const std::vector<PropertyBase*>& GetProperties() const;
|
|
||||||
virtual const std::vector<PropertyBase*>& GetDisplayProperties() const;
|
|
||||||
PropertyBase* GetProperty(const std::string& name) const;
|
PropertyBase* GetProperty(const std::string& name) const;
|
||||||
|
|
||||||
/** @brief Sends an Updated signal for all properties of this object. useful for real-time UI refresh. */
|
/** @brief Sends an Updated signal for all properties of this object. useful for real-time UI refresh. */
|
||||||
@@ -126,7 +124,7 @@ public:
|
|||||||
virtual void serialize(Archive::log_archive & ar, const unsigned int version) {}
|
virtual void serialize(Archive::log_archive & ar, const unsigned int version) {}
|
||||||
|
|
||||||
template <class ArchiveT>
|
template <class ArchiveT>
|
||||||
void save_override(ArchiveT &ar, const unsigned int version) {}
|
void save_override(ArchiveT &ar, const unsigned int version);
|
||||||
|
|
||||||
void SaveConfig(std::ostream &os, int version = 0);
|
void SaveConfig(std::ostream &os, int version = 0);
|
||||||
void LoadConfig(std::istream &is, int version = 0);
|
void LoadConfig(std::istream &is, int version = 0);
|
||||||
|
|||||||
@@ -5,23 +5,19 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <typeindex>
|
#include <typeindex> // Added
|
||||||
#include <boost/serialization/nvp.hpp>
|
#include <boost/serialization/nvp.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <vector>
|
||||||
#include <boost/type_traits/is_class.hpp>
|
#include <boost/type_traits/is_class.hpp>
|
||||||
#include <boost/mpl/bool.hpp>
|
#include <boost/mpl/bool.hpp>
|
||||||
#include <set>
|
#include <boost/serialization/serialization.hpp>
|
||||||
#include <boost/type_traits/is_base_of.hpp>
|
|
||||||
#include "Core/Archives.h"
|
#include "Core/Archives.h"
|
||||||
#include "Core/Signal.h"
|
#include "Core/Signal.h"
|
||||||
#include "Core/Object.h"
|
#include "Core/Object.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
namespace Archive {
|
|
||||||
class property_register_archive;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base class for properties to allow runtime listing and identification.
|
* @brief Base class for properties to allow runtime listing and identification.
|
||||||
*/
|
*/
|
||||||
@@ -31,7 +27,7 @@ public:
|
|||||||
virtual const std::string& GetName() const = 0;
|
virtual const std::string& GetName() const = 0;
|
||||||
virtual const char* GetTypeName() const = 0;
|
virtual const char* GetTypeName() const = 0;
|
||||||
virtual std::string GetValueAsString() const = 0;
|
virtual std::string GetValueAsString() const = 0;
|
||||||
virtual std::type_index GetTypeIndex() const = 0;
|
virtual std::type_index GetTypeIndex() const = 0; // Added
|
||||||
virtual const std::string& GetUnits() const = 0;
|
virtual const std::string& GetUnits() const = 0;
|
||||||
virtual void SetUnits(const std::string& units) = 0;
|
virtual void SetUnits(const std::string& units) = 0;
|
||||||
virtual const std::vector<std::string>& GetEnumLabels() const {
|
virtual const std::vector<std::string>& GetEnumLabels() const {
|
||||||
@@ -65,29 +61,42 @@ public:
|
|||||||
virtual void serialize(Archive::hrt_oarchive & 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::hrt_iarchive & ar, const unsigned int version) override = 0;
|
||||||
virtual void serialize(Archive::log_archive & ar, const unsigned int version) override = 0;
|
virtual void serialize(Archive::log_archive & ar, const unsigned int version) override = 0;
|
||||||
|
|
||||||
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Template class for typed properties.
|
* @brief Template class for typed properties.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Property : public PropertyBase {
|
class Property : public PropertyBase {
|
||||||
public:
|
public:
|
||||||
|
// PROXY: Use an existing variable as back-end storage
|
||||||
Property(Object* owner, const std::string& name, T* valuePtr, const std::string& units = "", const std::string& group = "")
|
Property(Object* owner, const std::string& name, T* valuePtr, const std::string& units = "", const std::string& group = "")
|
||||||
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(valuePtr), m_own(false),
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(valuePtr), m_own(false),
|
||||||
m_HasRange(false), m_HasDefault(false), m_ReadOnly(false) {
|
m_HasRange(false), m_HasDefault(false), m_ReadOnly(false) {
|
||||||
if (m_owner) m_owner->RegisterProperty(this);
|
if (m_owner) {
|
||||||
|
m_owner->RegisterProperty(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MANAGED: Create and own internal storage
|
||||||
Property(Object* owner, const std::string& name, const T& defaultValue = T(), const std::string& units = "", const std::string& group = "")
|
Property(Object* owner, const std::string& name, const T& defaultValue = T(), const std::string& units = "", const std::string& group = "")
|
||||||
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(new T(defaultValue)), m_own(true),
|
: m_owner(owner), m_name(name), m_units(units), m_group(group), m_value(new T(defaultValue)), m_own(true),
|
||||||
m_HasRange(false), m_HasDefault(true), m_Default(defaultValue), m_ReadOnly(false) {
|
m_HasRange(false), m_HasDefault(true), m_Default(defaultValue), m_ReadOnly(false) {
|
||||||
if (m_owner) m_owner->RegisterProperty(this);
|
if (m_owner) {
|
||||||
|
m_owner->RegisterProperty(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Property() { if (m_own) delete m_value; }
|
virtual ~Property() {
|
||||||
|
if (m_own) delete m_value;
|
||||||
|
}
|
||||||
|
|
||||||
// Identification
|
// Identification
|
||||||
virtual const std::string& GetName() const override { return m_name; }
|
virtual const std::string& GetName() const override { return m_name; }
|
||||||
@@ -98,18 +107,36 @@ public:
|
|||||||
virtual const std::string& GetGroup() const override { return m_group; }
|
virtual const std::string& GetGroup() const override { return m_group; }
|
||||||
virtual void SetGroup(const std::string& group) override { m_group = group; }
|
virtual void SetGroup(const std::string& group) override { m_group = group; }
|
||||||
|
|
||||||
|
|
||||||
std::string GetValueAsString() const override {
|
std::string GetValueAsString() const override {
|
||||||
try { return boost::lexical_cast<std::string>(*m_value); }
|
try {
|
||||||
catch (...) { std::stringstream ss; ss << *m_value; return ss.str(); }
|
return boost::lexical_cast<std::string>(*m_value);
|
||||||
|
} catch (const boost::bad_lexical_cast&) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << *m_value;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
const T& Get() const { return *m_value; }
|
const T& Get() const { return *m_value; }
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<std::is_arithmetic<U>::value, void>::type
|
||||||
|
ValidateT(T& val) {
|
||||||
|
if (m_HasRange) {
|
||||||
|
if (val < m_Min) val = m_Min;
|
||||||
|
if (val > m_Max) val = m_Max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<!std::is_arithmetic<U>::value, void>::type
|
||||||
|
ValidateT(T& val) {
|
||||||
|
}
|
||||||
|
|
||||||
void Set(const T& value) {
|
void Set(const T& value) {
|
||||||
T val = value;
|
T val = value;
|
||||||
if constexpr (std::is_arithmetic<T>::value) {
|
ValidateT<T>(val);
|
||||||
if (m_HasRange) { if (val < m_Min) val = m_Min; if (val > m_Max) val = m_Max; }
|
|
||||||
}
|
|
||||||
if (*m_value != val) {
|
if (*m_value != val) {
|
||||||
*m_value = val;
|
*m_value = val;
|
||||||
ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged);
|
ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged);
|
||||||
@@ -123,55 +150,65 @@ public:
|
|||||||
void SetReadOnly(bool ro) { m_ReadOnly = ro; }
|
void SetReadOnly(bool ro) { m_ReadOnly = ro; }
|
||||||
|
|
||||||
virtual bool IsReadOnly() const override { return m_ReadOnly; }
|
virtual bool IsReadOnly() const override { return m_ReadOnly; }
|
||||||
virtual bool HasRange() const override { return m_HasRange; }
|
|
||||||
virtual double GetMin() const override { return m_HasRange ? convert_to_double(m_Min) : 0.0; }
|
|
||||||
virtual double GetMax() const override { return m_HasRange ? convert_to_double(m_Max) : 0.0; }
|
|
||||||
|
|
||||||
const T& GetMinTyped() const { return m_Min; }
|
virtual bool HasRange() const override { return m_HasRange; }
|
||||||
const T& GetMaxTyped() const { return m_Max; }
|
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<std::is_arithmetic<U>::value, double>::type
|
||||||
|
GetMinT() const { return (double)m_Min; }
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<!std::is_arithmetic<U>::value, double>::type
|
||||||
|
GetMinT() const { return 0.0; }
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<std::is_arithmetic<U>::value, double>::type
|
||||||
|
GetMaxT() const { return (double)m_Max; }
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
typename std::enable_if<!std::is_arithmetic<U>::value, double>::type
|
||||||
|
GetMaxT() const { return 0.0; }
|
||||||
|
|
||||||
|
virtual double GetMin() const override { return GetMinT<T>(); }
|
||||||
|
virtual double GetMax() const override { return GetMaxT<T>(); }
|
||||||
|
|
||||||
virtual bool HasDefault() const override { return m_HasDefault; }
|
virtual bool HasDefault() const override { return m_HasDefault; }
|
||||||
virtual std::string GetDefaultValueAsString() const override {
|
virtual std::string GetDefaultValueAsString() const override {
|
||||||
try { return boost::lexical_cast<std::string>(m_Default); } catch (...) { return ""; }
|
try { return boost::lexical_cast<std::string>(m_Default); }
|
||||||
|
catch (...) { return ""; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operators
|
// Operators for seamless usage
|
||||||
operator const T&() const { return *m_value; }
|
operator const T&() const { return *m_value; }
|
||||||
Property& operator=(const T& value) { Set(value); return *this; }
|
Property& operator=(const T& value) {
|
||||||
|
Set(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signals
|
||||||
signals:
|
signals:
|
||||||
virtual void PropertyChanged() { ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged); }
|
virtual void PropertyChanged() { ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged); }
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename U>
|
|
||||||
static double convert_to_double(const U& val) {
|
|
||||||
return convert_to_double_impl(val, typename std::is_arithmetic<U>::type());
|
|
||||||
}
|
|
||||||
template <typename U>
|
|
||||||
static double convert_to_double_impl(const U& val, std::true_type) { return (double)val; }
|
|
||||||
template <typename U>
|
|
||||||
static double convert_to_double_impl(const U& val, std::false_type) { return 0.0; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Serialization
|
// Serialization
|
||||||
template <class ArchiveT>
|
template <class ArchiveT>
|
||||||
void serialize_helper(ArchiveT & ar, const unsigned int version) {
|
void serialize_impl(ArchiveT & ar, const unsigned int version) {
|
||||||
ar & boost::serialization::make_hrp(m_name.c_str(), *m_value, m_units.c_str());
|
ar & boost::serialization::make_nvp(m_name.c_str(), *m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::xml_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::text_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::text_oarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::text_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::text_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
virtual void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_helper(ar, v); }
|
void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_impl(ar, v); }
|
||||||
|
|
||||||
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) override;
|
virtual void Updated() override {
|
||||||
|
PropertyBase::Updated();
|
||||||
|
this->PropertyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void Updated() override { PropertyBase::Updated(); this->PropertyChanged(); }
|
private:
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_units;
|
std::string m_units;
|
||||||
std::string m_group;
|
std::string m_group;
|
||||||
@@ -187,7 +224,20 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Property specialized for enumerations.
|
* @brief Conveninent typedefs for common property types.
|
||||||
|
*/
|
||||||
|
typedef Property<std::string> StringProperty;
|
||||||
|
typedef Property<int> IntProperty;
|
||||||
|
typedef Property<unsigned int> UIntProperty;
|
||||||
|
typedef Property<long> LongProperty;
|
||||||
|
typedef Property<unsigned long> ULongProperty;
|
||||||
|
typedef Property<float> FloatProperty;
|
||||||
|
typedef Property<double> DoubleProperty;
|
||||||
|
typedef Property<Bool_t> BoolProperty;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Property specialized for enumerations, providing labels for GUI representations.
|
||||||
*/
|
*/
|
||||||
class EnumProperty : public Property<int> {
|
class EnumProperty : public Property<int> {
|
||||||
public:
|
public:
|
||||||
@@ -198,49 +248,68 @@ public:
|
|||||||
const char* GetTypeName() const override { return "Enum"; }
|
const char* GetTypeName() const override { return "Enum"; }
|
||||||
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(EnumProperty)); }
|
virtual std::type_index GetTypeIndex() const override { return std::type_index(typeid(EnumProperty)); }
|
||||||
|
|
||||||
template <class ArchiveT>
|
|
||||||
void serialize_enum_helper(ArchiveT & ar, const unsigned int version) {
|
|
||||||
ar & boost::serialization::make_hrp_enum(m_name.c_str(), *m_value, m_Labels, m_units.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::xml_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::text_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::text_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::hrt_oarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
virtual void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_enum_helper(ar, v); }
|
|
||||||
|
|
||||||
virtual void serialize(Archive::property_register_archive & ar, const unsigned int v) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_Labels;
|
std::vector<std::string> m_Labels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Macro to simplify property declaration within a class.
|
||||||
|
* Usage: ULIB_PROPERTY(float, Width, 1.0f)
|
||||||
|
* It creates a raw member m_Width and a Property proxy Width.
|
||||||
|
*/
|
||||||
|
#define ULIB_PROPERTY(type, name, defaultValue) \
|
||||||
|
type m_##name = defaultValue; \
|
||||||
|
Property<type> name = Property<type>(this, #name, &m_##name);
|
||||||
|
|
||||||
|
|
||||||
} // namespace uLib
|
} // namespace uLib
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Archive {
|
namespace Archive {
|
||||||
|
class property_register_archive;
|
||||||
|
} // namespace Archive
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
class property_register_archive
|
namespace boost {
|
||||||
: public boost::archive::detail::common_oarchive<property_register_archive> {
|
namespace archive {
|
||||||
protected:
|
namespace detail {
|
||||||
|
template <>
|
||||||
|
class interface_oarchive<uLib::Archive::property_register_archive>
|
||||||
|
: public uLib_interface_oarchive<uLib::Archive::property_register_archive> {};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace archive
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Archive {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A special archive that creates and registers Property proxies
|
||||||
|
* for any member it encounters wrapped in HRP().
|
||||||
|
*/
|
||||||
|
class property_register_archive :
|
||||||
|
public boost::archive::detail::common_oarchive<property_register_archive>
|
||||||
|
{
|
||||||
Object* m_Object;
|
Object* m_Object;
|
||||||
bool m_DisplayOnly;
|
|
||||||
public:
|
public:
|
||||||
friend class boost::archive::detail::interface_oarchive<property_register_archive>;
|
friend class boost::archive::detail::interface_oarchive<property_register_archive>;
|
||||||
friend class boost::archive::save_access;
|
friend class boost::archive::save_access;
|
||||||
|
|
||||||
using boost::archive::detail::common_oarchive<property_register_archive>::save_override;
|
typedef boost::archive::detail::common_oarchive<property_register_archive> detail_common_oarchive;
|
||||||
|
|
||||||
property_register_archive(Object* obj, bool displayOnly = false) :
|
property_register_archive(Object* obj) :
|
||||||
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
|
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
|
||||||
m_Object(obj), m_DisplayOnly(displayOnly) {
|
m_Object(obj) {}
|
||||||
if (obj) m_Visited.insert(dynamic_cast<const void*>(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T> property_register_archive &operator&(const T &t) { this->save_override(t); return *this; }
|
|
||||||
template<class T> property_register_archive &operator<<(const T &t) { this->save_override(t); return *this; }
|
|
||||||
|
|
||||||
std::string GetCurrentGroup() const {
|
std::string GetCurrentGroup() const {
|
||||||
std::string group;
|
std::string group;
|
||||||
@@ -251,91 +320,77 @@ public:
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> void register_property(Property<T>& p) {
|
// Core logic: encounter HRP -> Create Dynamic Property
|
||||||
save_property_impl(p.GetName().c_str(), const_cast<T&>(p.Get()), p.GetUnits().c_str(),
|
template<class T>
|
||||||
p.HasRange(), p.GetMinTyped(), p.GetMaxTyped(), p.IsReadOnly());
|
void save_override(const boost::serialization::hrp<T> &t) {
|
||||||
}
|
|
||||||
|
|
||||||
void register_enum_property(EnumProperty& p) {
|
|
||||||
if (!m_Object) return;
|
|
||||||
EnumProperty* newP = new EnumProperty(m_Object, p.GetName(), const_cast<int*>(&p.Get()), p.GetEnumLabels(), p.GetUnits(), GetCurrentGroup());
|
|
||||||
newP->SetReadOnly(p.IsReadOnly());
|
|
||||||
if (m_DisplayOnly) {
|
|
||||||
m_Object->RegisterDisplayProperty(newP);
|
|
||||||
Object* obj = m_Object;
|
|
||||||
Object::connect(newP, &PropertyBase::Updated, [obj]() { obj->Updated(); });
|
|
||||||
} else {
|
|
||||||
m_Object->RegisterDynamicProperty(newP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T> void save_property_impl(const char* name, T& val, const char* units, bool hasRange, const T& minVal, const T& maxVal, bool isReadOnly) {
|
|
||||||
if (m_Object) {
|
if (m_Object) {
|
||||||
Property<T>* p = new Property<T>(m_Object, name, &val, units ? units : "", GetCurrentGroup());
|
Property<T>* p = new Property<T>(m_Object, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
set_range_helper(p, hasRange, minVal, maxVal, typename std::is_arithmetic<T>::type());
|
if (t.has_range()) p->SetRange(t.min_val(), t.max_val());
|
||||||
p->SetReadOnly(isReadOnly);
|
if (t.has_default()) p->SetDefault(t.default_val());
|
||||||
if (m_DisplayOnly) {
|
p->SetReadOnly(t.is_read_only());
|
||||||
m_Object->RegisterDisplayProperty(p);
|
|
||||||
Object* obj = m_Object;
|
|
||||||
Object::connect(p, &PropertyBase::Updated, [obj]() { obj->Updated(); });
|
|
||||||
} else {
|
|
||||||
m_Object->RegisterDynamicProperty(p);
|
m_Object->RegisterDynamicProperty(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_override(const boost::serialization::hrp_val<T> &t) {
|
||||||
|
if (m_Object) {
|
||||||
|
// Note: hrp_val stores by value. Property usually points to existing data.
|
||||||
|
// But here we are registering properties from HRP wrappers.
|
||||||
|
// If it's hrp_val, it means it's an rvalue from a getter.
|
||||||
|
// The hrp_val wrapper itself owns the value.
|
||||||
|
// However, the property_register_archive is temporary.
|
||||||
|
// This is a bit tricky. Usually HRP(rvalue) is meant for read-only display.
|
||||||
|
// Let's use the address of the value in the wrapper, but mark it read-only.
|
||||||
|
Property<T>* p = new Property<T>(m_Object, t.name(), &const_cast<boost::serialization::hrp_val<T>&>(t).value(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
|
if (t.has_range()) p->SetRange(t.min_val(), t.max_val());
|
||||||
|
if (t.has_default()) p->SetDefault(t.default_val());
|
||||||
|
p->SetReadOnly(t.is_read_only());
|
||||||
|
m_Object->RegisterDynamicProperty(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U> static void set_range_helper(Property<U>* p, bool hasRange, const U& minVal, const U& maxVal, std::true_type) { if (hasRange) p->SetRange(minVal, maxVal); }
|
template<class T>
|
||||||
template<class U> static void set_range_helper(Property<U>* p, bool hasRange, const U& minVal, const U& maxVal, std::false_type) {}
|
void save_override(const boost::serialization::hrp_enum<T> &t) {
|
||||||
|
|
||||||
template<class T> void save_override(const boost::serialization::hrp<T> &t) {
|
|
||||||
// To handle T correctly without deduction issues, we assume T can be passed to save_property_impl
|
|
||||||
T dummy = T(); // Ensure we can construct T
|
|
||||||
save_property_impl(t.name(), const_cast<boost::serialization::hrp<T>&>(t).value(), t.units(), t.has_range(), t.has_range() ? t.min_val() : dummy, t.has_range() ? t.max_val() : dummy, t.is_read_only());
|
|
||||||
}
|
|
||||||
template<class T> void save_override(const boost::serialization::hrp_val<T> &t) {
|
|
||||||
T dummy = T();
|
|
||||||
save_property_impl(t.name(), const_cast<boost::serialization::hrp_val<T>&>(t).value(), t.units(), t.has_range(), t.has_range() ? t.min_val() : dummy, t.has_range() ? t.max_val() : dummy, t.is_read_only());
|
|
||||||
}
|
|
||||||
template<class T> void save_override(const boost::serialization::hrp_enum<T> &t) {
|
|
||||||
if (m_Object) {
|
if (m_Object) {
|
||||||
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
p->SetReadOnly(t.is_read_only());
|
p->SetReadOnly(t.is_read_only());
|
||||||
if (m_DisplayOnly) { m_Object->RegisterDisplayProperty(p); Object* obj = m_Object; Object::connect(p, &PropertyBase::Updated, [obj]() { obj->Updated(); }); }
|
m_Object->RegisterDynamicProperty(p);
|
||||||
else { m_Object->RegisterDynamicProperty(p); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<class T> void save_override(const boost::serialization::hrp_enum_val<T> &t) {
|
|
||||||
if (m_Object) {
|
|
||||||
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum_val<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
|
||||||
p->SetReadOnly(t.is_read_only());
|
|
||||||
if (m_DisplayOnly) { m_Object->RegisterDisplayProperty(p); Object* obj = m_Object; Object::connect(p, &PropertyBase::Updated, [obj]() { obj->Updated(); }); }
|
|
||||||
else { m_Object->RegisterDynamicProperty(p); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> void save_override(const boost::serialization::nvp<T> &t) {
|
template<class T>
|
||||||
|
void save_override(const boost::serialization::hrp_enum_val<T> &t) {
|
||||||
|
if (m_Object) {
|
||||||
|
EnumProperty* p = new EnumProperty(m_Object, t.name(), (int*)&const_cast<boost::serialization::hrp_enum_val<T>&>(t).value(), t.labels(), t.units() ? t.units() : "", GetCurrentGroup());
|
||||||
|
p->SetReadOnly(t.is_read_only());
|
||||||
|
m_Object->RegisterDynamicProperty(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle standard NVPs by recursing (important for base classes)
|
||||||
|
template<class T>
|
||||||
|
void save_override(const boost::serialization::nvp<T> &t) {
|
||||||
if (t.name()) m_GroupStack.push_back(t.name());
|
if (t.name()) m_GroupStack.push_back(t.name());
|
||||||
this->save_helper(t.const_value(), typename boost::is_class<T>::type());
|
this->save_helper(t.const_value(), typename boost::is_class<T>::type());
|
||||||
if (t.name()) m_GroupStack.pop_back();
|
if (t.name()) m_GroupStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_override(const std::string &t) {}
|
// Recursion for nested classes, ignore primitives
|
||||||
template<class T> void save_override(T * const & t) {
|
template<class T>
|
||||||
if (!t) return;
|
void save_override(const T &t) {
|
||||||
this->save_pointer_helper(t, typename boost::is_base_of<Object, T>::type());
|
this->save_helper(t, typename boost::is_class<T>::type());
|
||||||
}
|
}
|
||||||
template<class T> void save_pointer_helper(T* t, boost::mpl::true_) {
|
|
||||||
const void* ptr = dynamic_cast<const void*>(t);
|
|
||||||
if (m_Visited.find(ptr) != m_Visited.end()) return;
|
|
||||||
m_Visited.insert(ptr);
|
|
||||||
this->save_override(*t);
|
|
||||||
}
|
|
||||||
template<class T> void save_pointer_helper(T* t, boost::mpl::false_) {}
|
|
||||||
template<class T> void save_override(const T &t) { this->save_helper(t, typename boost::is_class<T>::type()); }
|
|
||||||
template<class T> void save_helper(const T &t, boost::mpl::true_) { boost::serialization::serialize_adl(*this, const_cast<T&>(t), 0); }
|
|
||||||
void save_helper(const std::string &t, boost::mpl::true_) {}
|
|
||||||
template<class T> void save_helper(const T &t, boost::mpl::false_) {}
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::true_) {
|
||||||
|
boost::serialization::serialize_adl(*this, const_cast<T&>(t), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void save_helper(const T &t, boost::mpl::false_) {}
|
||||||
|
|
||||||
|
// Required attribute overrides for common_oarchive
|
||||||
void save_override(const boost::archive::object_id_type & t) {}
|
void save_override(const boost::archive::object_id_type & t) {}
|
||||||
void save_override(const boost::archive::object_reference_type & t) {}
|
void save_override(const boost::archive::object_reference_type & t) {}
|
||||||
void save_override(const boost::archive::version_type & t) {}
|
void save_override(const boost::archive::version_type & t) {}
|
||||||
@@ -345,30 +400,30 @@ public:
|
|||||||
void save_override(const boost::archive::class_name_type & t) {}
|
void save_override(const boost::archive::class_name_type & t) {}
|
||||||
void save_override(const boost::archive::tracking_type & t) {}
|
void save_override(const boost::archive::tracking_type & t) {}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
std::vector<std::string> m_GroupStack;
|
std::vector<std::string> m_GroupStack;
|
||||||
std::set<const void*> m_Visited;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Archive
|
|
||||||
} // namespace uLib
|
|
||||||
|
|
||||||
namespace uLib {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void Property<T>::serialize(Archive::property_register_archive & ar, const unsigned int v) {
|
|
||||||
ar.register_property(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void EnumProperty::serialize(Archive::property_register_archive & ar, const unsigned int v) {
|
|
||||||
ar.register_enum_property(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Archive {
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience macro to automatically activate and register all HRP members
|
||||||
|
* as uLib properties. Usage: ULIB_ACTIVATE_PROPERTIES(obj)
|
||||||
|
*/
|
||||||
#define ULIB_ACTIVATE_PROPERTIES(obj) \
|
#define ULIB_ACTIVATE_PROPERTIES(obj) \
|
||||||
{ uLib::Archive::property_register_archive _ar_tmp(&(obj)); _ar_tmp & (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) \
|
#define ULIB_DECLARE_PROPERTIES(SelfType) \
|
||||||
private: \
|
private: \
|
||||||
struct _PropActivator { \
|
struct _PropActivator { \
|
||||||
@@ -379,31 +434,6 @@ private: \
|
|||||||
} _prop_activator{this};
|
} _prop_activator{this};
|
||||||
|
|
||||||
} // namespace Archive
|
} // namespace Archive
|
||||||
|
|
||||||
// Convenience macro: declares a named Property<T> member with a default value.
|
|
||||||
// Usage inside a class body (requires 'this' to be available, so use in-class initializer):
|
|
||||||
// ULIB_PROPERTY(int, MyProp, 42)
|
|
||||||
#define ULIB_PROPERTY(type, name, defaultVal) \
|
|
||||||
::uLib::Property<type> name{this, #name, (type)(defaultVal)};
|
|
||||||
|
|
||||||
// Common property type aliases
|
|
||||||
typedef Property<bool> BoolProperty;
|
|
||||||
typedef Property<int> IntProperty;
|
|
||||||
typedef Property<float> FloatProperty;
|
|
||||||
typedef Property<double> DoubleProperty;
|
|
||||||
typedef Property<std::string> StringProperty;
|
|
||||||
|
|
||||||
template <class ArchiveT>
|
|
||||||
void serialize_properties_helper(ArchiveT &ar, const std::vector<PropertyBase*> &props, unsigned int version) {
|
|
||||||
for (auto* prop : props) prop->serialize(ar, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ArchiveT>
|
|
||||||
void Object::serialize(ArchiveT &ar, const unsigned int version) {
|
|
||||||
ar & boost::serialization::make_nvp("InstanceName", this->GetInstanceName());
|
|
||||||
serialize_properties_helper(ar, this->GetProperties(), version);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace uLib
|
} // namespace uLib
|
||||||
|
|
||||||
#endif // U_CORE_PROPERTY_H
|
#endif // U_CORE_PROPERTY_H
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ inline const unsigned long VectorSplice(const _Tp &_it, const _Tp &_end,
|
|||||||
|
|
||||||
_Tp it = _it;
|
_Tp it = _it;
|
||||||
_Tp end = _end - 1;
|
_Tp end = _end - 1;
|
||||||
for (; it != end;) {
|
for (it; it != end;) {
|
||||||
if (_comp(*it, value))
|
if (_comp(*it, value))
|
||||||
it++;
|
it++;
|
||||||
else if (_comp(*end, value)) {
|
else if (_comp(*end, value)) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public AffineTransf
|
|||||||
virtual ~EmitterPrimary();
|
virtual ~EmitterPrimary();
|
||||||
|
|
||||||
// Metodo principale chiamato all'inizio di ogni evento
|
// Metodo principale chiamato all'inizio di ogni evento
|
||||||
virtual void GeneratePrimaries(G4Event*) override;
|
virtual void GeneratePrimaries(G4Event*);
|
||||||
|
|
||||||
virtual void Updated() override { ULIB_SIGNAL_EMIT(EmitterPrimary::Updated); }
|
virtual void Updated() override { ULIB_SIGNAL_EMIT(EmitterPrimary::Updated); }
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ class SkyPlaneEmitterPrimary : public EmitterPrimary
|
|||||||
SkyPlaneEmitterPrimary();
|
SkyPlaneEmitterPrimary();
|
||||||
virtual ~SkyPlaneEmitterPrimary();
|
virtual ~SkyPlaneEmitterPrimary();
|
||||||
|
|
||||||
virtual void GeneratePrimaries(G4Event*) override;
|
virtual void GeneratePrimaries(G4Event*);
|
||||||
|
|
||||||
void SetPlane(const uLib::Vector3f& p0, const uLib::Vector3f& normal);
|
void SetPlane(const uLib::Vector3f& p0, const uLib::Vector3f& normal);
|
||||||
void SetSkySize(const uLib::Vector2f& size);
|
void SetSkySize(const uLib::Vector2f& size);
|
||||||
@@ -72,7 +72,7 @@ class CylinderEmitterPrimary : public EmitterPrimary
|
|||||||
CylinderEmitterPrimary();
|
CylinderEmitterPrimary();
|
||||||
virtual ~CylinderEmitterPrimary();
|
virtual ~CylinderEmitterPrimary();
|
||||||
|
|
||||||
virtual void GeneratePrimaries(G4Event*) override;
|
virtual void GeneratePrimaries(G4Event*);
|
||||||
|
|
||||||
void SetRadius(float r);
|
void SetRadius(float r);
|
||||||
float GetRadius() const { return m_Radius; }
|
float GetRadius() const { return m_Radius; }
|
||||||
@@ -101,7 +101,7 @@ class QuadMeshEmitterPrimary : public EmitterPrimary
|
|||||||
virtual ~QuadMeshEmitterPrimary();
|
virtual ~QuadMeshEmitterPrimary();
|
||||||
|
|
||||||
// Metodo principale chiamato all'inizio di ogni evento
|
// Metodo principale chiamato all'inizio di ogni evento
|
||||||
virtual void GeneratePrimaries(G4Event*) override;
|
virtual void GeneratePrimaries(G4Event*);
|
||||||
|
|
||||||
void SetMesh(uLib::QuadMesh* mesh);
|
void SetMesh(uLib::QuadMesh* mesh);
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ list(APPEND HEADERS ${HEP_GEANT_HEADERS})
|
|||||||
set(LIBRARIES Eigen3::Eigen
|
set(LIBRARIES Eigen3::Eigen
|
||||||
${ROOT_LIBRARIES}
|
${ROOT_LIBRARIES}
|
||||||
${VTK_LIBRARIES}
|
${VTK_LIBRARIES}
|
||||||
VTK::ImagingHybrid
|
|
||||||
VTK::ImagingSources
|
|
||||||
${PACKAGE_LIBPREFIX}Math
|
${PACKAGE_LIBPREFIX}Math
|
||||||
${PACKAGE_LIBPREFIX}Detectors
|
${PACKAGE_LIBPREFIX}Detectors
|
||||||
${PACKAGE_LIBPREFIX}Geant)
|
${PACKAGE_LIBPREFIX}Geant)
|
||||||
@@ -58,7 +56,7 @@ set_target_properties(${libname} PROPERTIES
|
|||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTOUIC ON
|
AUTOUIC ON
|
||||||
AUTORCC ON)
|
AUTORCC ON)
|
||||||
target_link_libraries(${libname} PUBLIC ${LIBRARIES} Qt6::Widgets)
|
target_link_libraries(${libname} ${LIBRARIES} Qt6::Widgets)
|
||||||
|
|
||||||
install(TARGETS ${libname}
|
install(TARGETS ${libname}
|
||||||
EXPORT "uLibTargets"
|
EXPORT "uLibTargets"
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ int main(int argc, char** argv) {
|
|||||||
vtkTess.AddToViewer(viewer);
|
vtkTess.AddToViewer(viewer);
|
||||||
|
|
||||||
// Color them differently
|
// Color them differently
|
||||||
vtkBox.SetColor(0.8, 0.2, 0.2); // Redish box
|
vtkActor::SafeDownCast(vtkBox.GetProp())->GetProperty()->SetColor(0.8, 0.2, 0.2); // Redish box
|
||||||
vtkTess.SetColor(0.2, 0.8, 0.2); // Greenish tess
|
vtkActor::SafeDownCast(vtkTess.GetProp())->GetProperty()->SetColor(0.2, 0.8, 0.2); // Greenish tess
|
||||||
|
|
||||||
// Position tessellated solid away from box
|
// Position tessellated solid away from box
|
||||||
Matrix4f trans = Matrix4f::Identity();
|
Matrix4f trans = Matrix4f::Identity();
|
||||||
|
|||||||
@@ -13,104 +13,43 @@
|
|||||||
#include <vtkCubeSource.h>
|
#include <vtkCubeSource.h>
|
||||||
#include <vtkPolyDataMapper.h>
|
#include <vtkPolyDataMapper.h>
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
#include <vtkAssembly.h>
|
|
||||||
#include <vtkTransform.h>
|
|
||||||
#include <vtkMatrix4x4.h>
|
|
||||||
#include <Geant4/G4VPhysicalVolume.hh>
|
|
||||||
#include "Vtk/Math/vtkDense.h"
|
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Vtk {
|
namespace Vtk {
|
||||||
|
|
||||||
vtkBoxSolid::vtkBoxSolid(Geant::BoxSolid *content)
|
vtkBoxSolid::vtkBoxSolid(Geant::BoxSolid *content)
|
||||||
: vtkGeantSolid(content), m_BoxContent(content), m_BoxPuppet(nullptr) {
|
: vtkGeantSolid(content), m_BoxContent(content) {
|
||||||
|
// Re-run Update for box-specific pipe
|
||||||
if (m_BoxContent && m_BoxContent->GetObject()) {
|
|
||||||
m_BoxPuppet = new vtkContainerBox(m_BoxContent->GetObject());
|
|
||||||
// Use the specialized box puppet's representation as our main prop
|
|
||||||
this->SetProp(m_BoxPuppet->GetProp());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect the model's Updated event to updateTransform to ensure VTK sync
|
|
||||||
Object::connect(m_BoxContent, &uLib::Object::Updated, this, &vtkBoxSolid::UpdateTransform);
|
|
||||||
|
|
||||||
// Initial sync
|
|
||||||
this->Update();
|
this->Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
vtkBoxSolid::~vtkBoxSolid() {
|
vtkBoxSolid::~vtkBoxSolid() {}
|
||||||
if (m_BoxPuppet) {
|
|
||||||
delete m_BoxPuppet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vtkBoxSolid::Update() {
|
void vtkBoxSolid::Update() {
|
||||||
this->UpdateGeometry();
|
this->UpdateGeometry();
|
||||||
this->UpdateTransform();
|
this->UpdateTransform();
|
||||||
// Ensure base Puppet properties (color, opacity, etc) are applied
|
|
||||||
this->Puppet::Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vtkBoxSolid::SyncFromVtk() {
|
|
||||||
vtkProp3D *root = vtkProp3D::SafeDownCast(this->GetProp());
|
|
||||||
if (root && m_BoxContent) {
|
|
||||||
vtkMatrix4x4 *rootMat = root->GetUserMatrix();
|
|
||||||
if (rootMat) {
|
|
||||||
Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
|
|
||||||
m_BoxContent->SetTransform(vtkWorld);
|
|
||||||
m_BoxContent->Updated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtkBoxSolid::UpdateGeometry() {
|
void vtkBoxSolid::UpdateGeometry() {
|
||||||
if (!m_BoxContent || !m_BoxContent->GetObject() || !m_BoxPuppet) {
|
if (!m_BoxContent || !m_BoxContent->GetObject()) {
|
||||||
// Fallback to base tessellation if no model object is available
|
// Fallback to base tessellation if no model object
|
||||||
vtkGeantSolid::UpdateGeometry();
|
vtkGeantSolid::UpdateGeometry();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The vtkContainerBox manages its own geometry update
|
// Use the underlying ContainerBox for precise geometry
|
||||||
m_BoxPuppet->Update();
|
Vector3f size = m_BoxContent->GetObject()->GetSize();
|
||||||
}
|
|
||||||
|
|
||||||
void vtkBoxSolid::UpdateTransform() {
|
vtkNew<vtkCubeSource> cube;
|
||||||
if (!m_BoxContent || !m_BoxPuppet) {
|
cube->SetXLength(size(0));
|
||||||
vtkGeantSolid::UpdateTransform();
|
cube->SetYLength(size(1));
|
||||||
return;
|
cube->SetZLength(size(2));
|
||||||
}
|
cube->Update();
|
||||||
|
|
||||||
// 1. Sync the inner box TRS (local box properties like size and offset)
|
vtkPolyData *poly = GetPolyData();
|
||||||
m_BoxPuppet->Update();
|
if (poly) {
|
||||||
|
poly->ShallowCopy(cube->GetOutput());
|
||||||
// 2. Sync the Geant4-level placement (world position/rotation)
|
poly->Modified();
|
||||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
|
||||||
if (root && m_BoxContent->GetPhysical()) {
|
|
||||||
auto *phys = m_BoxContent->GetPhysical();
|
|
||||||
G4ThreeVector pos = phys->GetTranslation();
|
|
||||||
const G4RotationMatrix *rot = phys->GetRotation();
|
|
||||||
|
|
||||||
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
|
|
||||||
transform->Identity();
|
|
||||||
transform->Translate(pos.x(), pos.y(), pos.z());
|
|
||||||
|
|
||||||
if (rot) {
|
|
||||||
// G4RotationMatrix stores the inverse of the rotation for placement
|
|
||||||
G4RotationMatrix invRot = rot->inverse();
|
|
||||||
double elements[16] = {
|
|
||||||
invRot.xx(), invRot.xy(), invRot.xz(), 0,
|
|
||||||
invRot.yx(), invRot.yy(), invRot.yz(), 0,
|
|
||||||
invRot.zx(), invRot.zy(), invRot.zz(), 0,
|
|
||||||
0, 0, 0, 1
|
|
||||||
};
|
|
||||||
vtkSmartPointer<vtkMatrix4x4> mat = vtkSmartPointer<vtkMatrix4x4>::New();
|
|
||||||
mat->DeepCopy(elements);
|
|
||||||
transform->Concatenate(mat);
|
|
||||||
}
|
|
||||||
// Apply the Geant4 transform on top of the local box's UserMatrix
|
|
||||||
root->SetUserTransform(transform);
|
|
||||||
} else if (root) {
|
|
||||||
root->SetUserTransform(nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,7 @@
|
|||||||
#ifndef U_VTKBOXSOLID_H
|
#ifndef U_VTKBOXSOLID_H
|
||||||
#define U_VTKBOXSOLID_H
|
#define U_VTKBOXSOLID_H
|
||||||
|
|
||||||
#include "Core/Types.h"
|
|
||||||
#include "Core/Property.h"
|
|
||||||
#include "Core/Serializable.h"
|
|
||||||
|
|
||||||
#include "vtkGeantSolid.h"
|
#include "vtkGeantSolid.h"
|
||||||
#include "Vtk/Math/vtkContainerBox.h"
|
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Vtk {
|
namespace Vtk {
|
||||||
@@ -40,27 +35,15 @@ namespace Vtk {
|
|||||||
* @brief VTK Puppet for visualizing a Geant::BoxSolid.
|
* @brief VTK Puppet for visualizing a Geant::BoxSolid.
|
||||||
*/
|
*/
|
||||||
class vtkBoxSolid : public vtkGeantSolid {
|
class vtkBoxSolid : public vtkGeantSolid {
|
||||||
uLibTypeMacro(vtkBoxSolid, uLib::Vtk::vtkGeantSolid)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
vtkBoxSolid(Geant::BoxSolid *content);
|
vtkBoxSolid(Geant::BoxSolid *content);
|
||||||
virtual ~vtkBoxSolid();
|
virtual ~vtkBoxSolid();
|
||||||
|
|
||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
virtual void UpdateGeometry() override;
|
virtual void UpdateGeometry() override;
|
||||||
virtual void UpdateTransform() override;
|
|
||||||
virtual void SyncFromVtk() override;
|
|
||||||
|
|
||||||
template <typename Ar>
|
|
||||||
void serialize(Ar &ar, const unsigned int version) {
|
|
||||||
ar & NVP("BoxSolid", *m_BoxContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
Geant::BoxSolid *m_BoxContent;
|
Geant::BoxSolid *m_BoxContent;
|
||||||
vtkContainerBox *m_BoxPuppet;
|
|
||||||
|
|
||||||
ULIB_DECLARE_PROPERTIES(vtkBoxSolid)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vtk
|
} // namespace Vtk
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
|
|
||||||
virtual class vtkPolyData *GetPolyData() const override;
|
virtual class vtkPolyData *GetPolyData() const override;
|
||||||
|
|
||||||
virtual void Update() override;
|
virtual void Update();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void InstallPipe();
|
virtual void InstallPipe();
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ struct ContainerBoxData {
|
|||||||
vtkSmartPointer<vtkMatrix4x4> m_Affine;
|
vtkSmartPointer<vtkMatrix4x4> m_Affine;
|
||||||
uLib::Connection m_UpdateSignal;
|
uLib::Connection m_UpdateSignal;
|
||||||
|
|
||||||
|
|
||||||
ContainerBoxData() : m_Cube(vtkSmartPointer<vtkActor>::New()),
|
ContainerBoxData() : m_Cube(vtkSmartPointer<vtkActor>::New()),
|
||||||
m_Axes(vtkSmartPointer<vtkActor>::New()),
|
m_Axes(vtkSmartPointer<vtkActor>::New()),
|
||||||
m_VtkAsm(vtkSmartPointer<vtkAssembly>::New()),
|
m_VtkAsm(vtkSmartPointer<vtkAssembly>::New()),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
vtkContainerBox(Content *content);
|
vtkContainerBox(Content *content);
|
||||||
~vtkContainerBox();
|
~vtkContainerBox();
|
||||||
|
|
||||||
virtual class vtkPolyData *GetPolyData() const override;
|
virtual class vtkPolyData *GetPolyData() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the VTK representation from the internal state.
|
* @brief Updates the VTK representation from the internal state.
|
||||||
@@ -62,9 +62,9 @@ protected:
|
|||||||
virtual void InstallPipe();
|
virtual void InstallPipe();
|
||||||
|
|
||||||
struct ContainerBoxData *d;
|
struct ContainerBoxData *d;
|
||||||
ContainerBox *m_Content;
|
Content *m_Content;
|
||||||
|
bool m_BlockUpdate = false;
|
||||||
|
|
||||||
ULIB_DECLARE_PROPERTIES(vtkContainerBox)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vtk
|
} // namespace Vtk
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public:
|
|||||||
vtkPolyData* polydata = nullptr;
|
vtkPolyData* polydata = nullptr;
|
||||||
if (vtkActor *actor = vtkActor::SafeDownCast(m_Prop)) {
|
if (vtkActor *actor = vtkActor::SafeDownCast(m_Prop)) {
|
||||||
if (actor->GetMapper()) {
|
if (actor->GetMapper()) {
|
||||||
polydata = vtkPolyData::SafeDownCast(actor->GetMapper()->GetInput());
|
polydata = vtkPolyData::SafeDownCast(actor->GetMapper()->GetDataSetInput());
|
||||||
}
|
}
|
||||||
} else if (vtkAssembly *asm_p = vtkAssembly::SafeDownCast(m_Prop)) {
|
} else if (vtkAssembly *asm_p = vtkAssembly::SafeDownCast(m_Prop)) {
|
||||||
vtkPropCollection *parts = asm_p->GetParts();
|
vtkPropCollection *parts = asm_p->GetParts();
|
||||||
@@ -192,7 +192,7 @@ public:
|
|||||||
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
|
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
|
||||||
vtkActor *a = vtkActor::SafeDownCast(parts->GetNextProp());
|
vtkActor *a = vtkActor::SafeDownCast(parts->GetNextProp());
|
||||||
if (a && a->GetMapper()) {
|
if (a && a->GetMapper()) {
|
||||||
polydata = vtkPolyData::SafeDownCast(a->GetMapper()->GetInput());
|
polydata = vtkPolyData::SafeDownCast(a->GetMapper()->GetDataSetInput());
|
||||||
if (polydata) break;
|
if (polydata) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -560,55 +560,28 @@ bool Puppet::IsSelected() const
|
|||||||
return pd->m_Selected;
|
return pd->m_Selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Puppet::ApplyPuppetTransform(vtkProp3D* prop)
|
|
||||||
{
|
|
||||||
if (!prop) return;
|
|
||||||
if (auto* content = this->GetContent()) {
|
|
||||||
if (auto* tr = dynamic_cast<uLib::TRS*>(content)) {
|
|
||||||
vtkNew<vtkMatrix4x4> m;
|
|
||||||
Matrix4fToVtk(tr->GetMatrix(), m);
|
|
||||||
prop->SetUserMatrix(m);
|
|
||||||
prop->Modified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Puppet::SyncFromVtk()
|
|
||||||
{
|
|
||||||
if (auto* content = this->GetContent()) {
|
|
||||||
if (auto* tr = dynamic_cast<uLib::TRS*>(content)) {
|
|
||||||
if (auto* proxy = this->GetProxyProp()) {
|
|
||||||
if (vtkMatrix4x4* mat = proxy->GetUserMatrix()) {
|
|
||||||
tr->FromMatrix(VtkToMatrix4f(mat));
|
|
||||||
content->Updated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Puppet::Update()
|
void Puppet::Update()
|
||||||
{
|
{
|
||||||
// Apply content transform via virtual GetProp() / ApplyPuppetTransform(),
|
// Derived classes should have updated the transform if they override Update()
|
||||||
// so all derived classes benefit without duplicating the matrix code.
|
// or we can apply base transform if it's default:
|
||||||
this->ApplyPuppetTransform(vtkProp3D::SafeDownCast(this->GetProp()));
|
// pd->ApplyTransform(pd->m_Prop);
|
||||||
|
|
||||||
// Use virtual GetProp() for appearance so overriders (e.g. vtkVoxImage)
|
pd->ApplyAppearance(pd->m_Prop);
|
||||||
// that never call SetProp() are handled correctly.
|
|
||||||
pd->ApplyAppearance(this->GetProp());
|
|
||||||
|
|
||||||
if (pd->m_Selected) {
|
if (pd->m_Selected) {
|
||||||
pd->UpdateHighlight();
|
pd->UpdateHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* prop = this->GetProp()) {
|
if (pd->m_Prop) {
|
||||||
if (pd->m_ShowBoundingBox && pd->m_OutlineSource) {
|
if (pd->m_ShowBoundingBox) {
|
||||||
double* bounds = prop->GetBounds();
|
double* bounds = pd->m_Prop->GetBounds();
|
||||||
pd->m_OutlineSource->SetBounds(bounds);
|
pd->m_OutlineSource->SetBounds(bounds);
|
||||||
pd->m_OutlineSource->Update();
|
pd->m_OutlineSource->Update();
|
||||||
}
|
}
|
||||||
if (pd->m_ShowScaleMeasures && pd->m_CubeAxesActor) {
|
|
||||||
pd->m_CubeAxesActor->SetBounds(prop->GetBounds());
|
if (pd->m_ShowScaleMeasures) {
|
||||||
|
double* bounds = pd->m_Prop->GetBounds();
|
||||||
|
pd->m_CubeAxesActor->SetBounds(bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,7 +598,6 @@ void Puppet::Update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor)
|
void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
|
||||||
#include <boost/type_traits/is_base_of.hpp>
|
|
||||||
|
|
||||||
// vtk classes forward declaration //
|
// vtk classes forward declaration //
|
||||||
class vtkProp;
|
class vtkProp;
|
||||||
@@ -108,7 +106,7 @@ uLibTypeMacro(Puppet, uLib::Object)
|
|||||||
* This method should be called when the VTK representation has been modified
|
* This method should be called when the VTK representation has been modified
|
||||||
* (e.g., via a gizmo) and the changes need to be pushed back to the model.
|
* (e.g., via a gizmo) and the changes need to be pushed back to the model.
|
||||||
*/
|
*/
|
||||||
virtual void SyncFromVtk();
|
virtual void SyncFromVtk() {}
|
||||||
|
|
||||||
enum Representation {
|
enum Representation {
|
||||||
Points = 0,
|
Points = 0,
|
||||||
@@ -129,10 +127,10 @@ uLibTypeMacro(Puppet, uLib::Object)
|
|||||||
|
|
||||||
vtkRendererCollection *GetRenderers() const;
|
vtkRendererCollection *GetRenderers() const;
|
||||||
|
|
||||||
const std::vector<uLib::PropertyBase *> &GetDisplayProperties() const override {
|
const std::vector<uLib::PropertyBase *> &GetDisplayProperties() const {
|
||||||
return m_DisplayProperties;
|
return m_DisplayProperties;
|
||||||
}
|
}
|
||||||
void RegisterDisplayProperty(uLib::PropertyBase *prop) override {
|
void RegisterDisplayProperty(uLib::PropertyBase *prop) {
|
||||||
m_DisplayProperties.push_back(prop);
|
m_DisplayProperties.push_back(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +149,6 @@ protected:
|
|||||||
|
|
||||||
void ApplyAppearance(vtkProp *prop);
|
void ApplyAppearance(vtkProp *prop);
|
||||||
void ApplyTransform(vtkProp3D *p3d);
|
void ApplyTransform(vtkProp3D *p3d);
|
||||||
void ApplyPuppetTransform(vtkProp3D *p3d);
|
|
||||||
|
|
||||||
std::vector<uLib::PropertyBase *> m_DisplayProperties;
|
std::vector<uLib::PropertyBase *> m_DisplayProperties;
|
||||||
mutable uLib::RecursiveMutex m_UpdateMutex;
|
mutable uLib::RecursiveMutex m_UpdateMutex;
|
||||||
@@ -182,17 +179,10 @@ class display_properties_archive
|
|||||||
: public boost::archive::detail::common_oarchive<
|
: public boost::archive::detail::common_oarchive<
|
||||||
display_properties_archive> {
|
display_properties_archive> {
|
||||||
public:
|
public:
|
||||||
friend class boost::archive::detail::interface_oarchive<display_properties_archive>;
|
display_properties_archive(Vtk::Puppet *puppet)
|
||||||
friend class boost::archive::save_access;
|
|
||||||
|
|
||||||
using boost::archive::detail::common_oarchive<display_properties_archive>::save_override;
|
|
||||||
display_properties_archive(Vtk::Puppet *p)
|
|
||||||
: boost::archive::detail::common_oarchive<display_properties_archive>(
|
: boost::archive::detail::common_oarchive<display_properties_archive>(
|
||||||
boost::archive::no_header),
|
boost::archive::no_header),
|
||||||
m_Puppet(p) {
|
m_Puppet(puppet) {}
|
||||||
if (p)
|
|
||||||
m_Visited.insert(dynamic_cast<const void *>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetCurrentGroup() const {
|
std::string GetCurrentGroup() const {
|
||||||
std::string group;
|
std::string group;
|
||||||
@@ -244,24 +234,6 @@ public:
|
|||||||
m_GroupStack.pop_back();
|
m_GroupStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow pointers to discover properties in child objects
|
|
||||||
template<class T>
|
|
||||||
void save_override(T * const & t) {
|
|
||||||
if (!t) return;
|
|
||||||
this->save_pointer_helper(t, typename boost::is_base_of<uLib::Object, T>::type());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void save_pointer_helper(T* t, boost::mpl::true_) {
|
|
||||||
const void* ptr = dynamic_cast<const void*>(t);
|
|
||||||
if (m_Visited.find(ptr) != m_Visited.end()) return;
|
|
||||||
m_Visited.insert(ptr);
|
|
||||||
this->save_override(*t);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void save_pointer_helper(T* t, boost::mpl::false_) {}
|
|
||||||
|
|
||||||
// Recursion for nested classes, ignore primitives
|
// Recursion for nested classes, ignore primitives
|
||||||
template <class T> void save_override(const T &t) {
|
template <class T> void save_override(const T &t) {
|
||||||
this->save_helper(t, typename boost::is_class<T>::type());
|
this->save_helper(t, typename boost::is_class<T>::type());
|
||||||
@@ -271,8 +243,6 @@ public:
|
|||||||
boost::serialization::serialize_adl(*this, const_cast<T &>(t), 0);
|
boost::serialization::serialize_adl(*this, const_cast<T &>(t), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_helper(const std::string &t, boost::mpl::true_) {}
|
|
||||||
|
|
||||||
template <class T> void save_helper(const T &t, boost::mpl::false_) {}
|
template <class T> void save_helper(const T &t, boost::mpl::false_) {}
|
||||||
|
|
||||||
void save_override(const boost::archive::object_id_type &t) {}
|
void save_override(const boost::archive::object_id_type &t) {}
|
||||||
@@ -284,25 +254,9 @@ public:
|
|||||||
void save_override(const boost::archive::class_name_type &t) {}
|
void save_override(const boost::archive::class_name_type &t) {}
|
||||||
void save_override(const boost::archive::tracking_type &t) {}
|
void save_override(const boost::archive::tracking_type &t) {}
|
||||||
|
|
||||||
// Called by Property<T>::serialize() and EnumProperty::serialize() to
|
|
||||||
// directly register an existing property object as a display property.
|
|
||||||
void register_property(uLib::PropertyBase &p) {
|
|
||||||
if (m_Puppet) {
|
|
||||||
m_Puppet->RegisterDisplayProperty(&p);
|
|
||||||
Vtk::Puppet *puppet = m_Puppet;
|
|
||||||
uLib::Object::connect(&p, &uLib::PropertyBase::Updated,
|
|
||||||
[puppet]() { puppet->Update(); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_enum_property(uLib::EnumProperty &p) {
|
|
||||||
register_property(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vtk::Puppet *m_Puppet;
|
Vtk::Puppet *m_Puppet;
|
||||||
std::vector<std::string> m_GroupStack;
|
std::vector<std::string> m_GroupStack;
|
||||||
std::set<const void *> m_Visited;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Archive
|
} // namespace Archive
|
||||||
|
|||||||
Reference in New Issue
Block a user