refactor: migrate vtk classes to use ObjectWrapper for model management and update registration logic
This commit is contained in:
@@ -1,53 +1,55 @@
|
||||
#ifndef U_CORE_OBJECTFACTORY_H
|
||||
#define U_CORE_OBJECTFACTORY_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "Core/Object.h"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace uLib {
|
||||
|
||||
/**
|
||||
* @brief Singleton factory for dynamic Object instantiation based on class name.
|
||||
* @brief Singleton factory for dynamic Object instantiation based on class
|
||||
* name.
|
||||
*/
|
||||
class ObjectFactory {
|
||||
public:
|
||||
typedef std::function<Object*()> FactoryFunction;
|
||||
typedef std::function<Object *()> FactoryFunction;
|
||||
|
||||
/** @brief Get the singleton instance. */
|
||||
static ObjectFactory& Instance();
|
||||
/** @brief Get the singleton instance. */
|
||||
static ObjectFactory &Instance();
|
||||
|
||||
/** @brief Register a factory function for a given class name. */
|
||||
void Register(const std::string& className, FactoryFunction func);
|
||||
/** @brief Register a factory function for a given class name. */
|
||||
void Register(const std::string &className, FactoryFunction func);
|
||||
|
||||
/** @brief Create a new instance of the specified class. */
|
||||
Object* Create(const std::string& className);
|
||||
/** @brief Create a new instance of the specified class. */
|
||||
Object *Create(const std::string &className);
|
||||
|
||||
/** @brief Get the names of all registered classes. */
|
||||
std::vector<std::string> GetRegisteredClasses() const;
|
||||
/** @brief Get the names of all registered classes. */
|
||||
std::vector<std::string> GetRegisteredClasses() const;
|
||||
|
||||
private:
|
||||
ObjectFactory() = default;
|
||||
~ObjectFactory() = default;
|
||||
ObjectFactory() = default;
|
||||
~ObjectFactory() = default;
|
||||
|
||||
// Prevent copy and assignment
|
||||
ObjectFactory(const ObjectFactory&) = delete;
|
||||
ObjectFactory& operator=(const ObjectFactory&) = delete;
|
||||
// Prevent copy and assignment
|
||||
ObjectFactory(const ObjectFactory &) = delete;
|
||||
ObjectFactory &operator=(const ObjectFactory &) = delete;
|
||||
|
||||
std::map<std::string, FactoryFunction> m_factoryMap;
|
||||
std::map<std::string, FactoryFunction> m_factoryMap;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper class to statically register a factory function.
|
||||
*/
|
||||
template <typename T>
|
||||
class ObjectRegistrar {
|
||||
template <typename T> class ObjectRegistrar {
|
||||
public:
|
||||
ObjectRegistrar(const std::string& className) {
|
||||
ObjectFactory::Instance().Register(className, []() -> Object* { return new T(); });
|
||||
}
|
||||
ObjectRegistrar(const std::string &className) {
|
||||
ObjectFactory::Instance().Register(className,
|
||||
[]() -> Object * { return new T(); });
|
||||
}
|
||||
};
|
||||
|
||||
#define ULIB_REG_CONCAT_IMPL(a, b) a##b
|
||||
@@ -57,11 +59,63 @@ public:
|
||||
* @brief Macro to register a class to the factory.
|
||||
* Put this in the .cpp file of the class.
|
||||
*/
|
||||
#define ULIB_REGISTER_OBJECT(className) \
|
||||
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(#className);
|
||||
#define ULIB_REGISTER_OBJECT(className) \
|
||||
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT( \
|
||||
g_ObjectRegistrar_, __LINE__)(#className);
|
||||
|
||||
#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \
|
||||
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(registeredName);
|
||||
#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \
|
||||
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT( \
|
||||
g_ObjectRegistrar_, __LINE__)(registeredName);
|
||||
|
||||
template <typename T> class ObjectWrapper {
|
||||
public:
|
||||
ObjectWrapper(const std::string &className) {
|
||||
ObjectFactory::Instance().Register(className,
|
||||
[]() -> Object * { return new T(); });
|
||||
}
|
||||
|
||||
ObjectWrapper(T *model) : m_model(model) {}
|
||||
|
||||
template <typename U = T,
|
||||
typename = std::enable_if_t<std::is_default_constructible_v<U>>>
|
||||
ObjectWrapper() : m_model(new T()) {}
|
||||
|
||||
ObjectWrapper(const ObjectWrapper &other) : m_model(other.m_model) {}
|
||||
|
||||
ObjectWrapper &operator=(const ObjectWrapper &other) {
|
||||
m_model = other.m_model;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectWrapper(ObjectWrapper &&other) noexcept
|
||||
: m_model(std::move(other.m_model)) {}
|
||||
|
||||
ObjectWrapper &operator=(ObjectWrapper &&other) noexcept {
|
||||
m_model = std::move(other.m_model);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ObjectWrapper() = default;
|
||||
|
||||
T *operator->() const { return m_model.get(); }
|
||||
|
||||
T &operator*() const { return *m_model; }
|
||||
|
||||
T *get() const { return m_model.get(); }
|
||||
|
||||
bool operator==(const ObjectWrapper &other) const {
|
||||
return m_model == other.m_model;
|
||||
}
|
||||
|
||||
bool operator!=(const ObjectWrapper &other) const {
|
||||
return m_model != other.m_model;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_model != nullptr; }
|
||||
|
||||
protected:
|
||||
SmartPointer<T> m_model;
|
||||
};
|
||||
|
||||
} // namespace uLib
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace uLib {
|
||||
@@ -50,7 +51,11 @@ public:
|
||||
* If ptr is nullptr, a new T is allocated (legacy behavior).
|
||||
*/
|
||||
explicit SmartPointer(T* ptr = nullptr) : m_counter(nullptr) {
|
||||
if (!ptr) ptr = new T();
|
||||
if (!ptr) {
|
||||
if constexpr (std::is_default_constructible_v<T>) {
|
||||
ptr = new T();
|
||||
}
|
||||
}
|
||||
if (ptr) m_counter = new ReferenceCounter(ptr);
|
||||
}
|
||||
|
||||
@@ -156,6 +161,11 @@ public:
|
||||
*/
|
||||
T* get() const noexcept { return m_counter ? m_counter->ptr : nullptr; }
|
||||
|
||||
/**
|
||||
* @brief Implicit conversion to raw pointer (legacy compatibility).
|
||||
*/
|
||||
operator T*() const noexcept { return get(); }
|
||||
|
||||
/**
|
||||
* @brief Returns the number of SmartPointers sharing ownership.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
set( TESTS
|
||||
SmartVectorTest
|
||||
SmartPointerTest
|
||||
ObjectWrapperTest
|
||||
VectorTest
|
||||
ObjectFlagsTest
|
||||
ObjectParametersTest
|
||||
|
||||
26
src/Core/testing/ObjectWrapperTest.cpp
Normal file
26
src/Core/testing/ObjectWrapperTest.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include <iostream>
|
||||
|
||||
struct NonDefault {
|
||||
NonDefault(int) {}
|
||||
};
|
||||
|
||||
struct Default {
|
||||
Default() : value(42) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "Testing ObjectWrapper with Default Constructible type..." << std::endl;
|
||||
uLib::ObjectWrapper<Default> w1;
|
||||
|
||||
std::cout << "Testing ObjectWrapper with Non-Default Constructible type..." << std::endl;
|
||||
NonDefault nd(10);
|
||||
uLib::ObjectWrapper<NonDefault> w2(&nd);
|
||||
|
||||
// The following would NOT compile without SFINAE:
|
||||
// uLib::ObjectWrapper<NonDefault> w3;
|
||||
|
||||
std::cout << "Tests passed (compilation and manual instantiation)!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/Assembly.h"
|
||||
#include "Math/ContainerBox.h"
|
||||
#include "Math/Cylinder.h"
|
||||
#include "Math/Geometry.h"
|
||||
#include "Math/TriangleMesh.h"
|
||||
#include "Math/QuadMesh.h"
|
||||
#include "Math/VoxImage.h"
|
||||
#include "Math/Assembly.h"
|
||||
#include "Math/StructuredData.h"
|
||||
#include "Math/TriangleMesh.h"
|
||||
#include "Math/VoxImage.h"
|
||||
|
||||
namespace uLib {
|
||||
|
||||
@@ -14,8 +14,6 @@ ULIB_REGISTER_OBJECT(TRS)
|
||||
ULIB_REGISTER_OBJECT(ContainerBox)
|
||||
ULIB_REGISTER_OBJECT(Cylinder)
|
||||
ULIB_REGISTER_OBJECT(Assembly)
|
||||
ULIB_REGISTER_OBJECT(CylindricalGeometry)
|
||||
ULIB_REGISTER_OBJECT(SphericalGeometry)
|
||||
ULIB_REGISTER_OBJECT(TriangleMesh)
|
||||
ULIB_REGISTER_OBJECT(QuadMesh)
|
||||
ULIB_REGISTER_OBJECT_NAME(VoxImage<Voxel>, "VoxImage")
|
||||
|
||||
@@ -73,13 +73,13 @@ DetectorChamber::~DetectorChamber() {
|
||||
}
|
||||
|
||||
DetectorChamber::Content *DetectorChamber::GetContent() const {
|
||||
return static_cast<Content *>(m_Content);
|
||||
return static_cast<Content *>(this->m_model.get());
|
||||
}
|
||||
|
||||
void DetectorChamber::Update() {
|
||||
this->BaseClass::Update();
|
||||
|
||||
if (!m_Content) return;
|
||||
if (!this->m_model) return;
|
||||
Content *c = this->GetContent();
|
||||
Vector3f size = c->GetSize();
|
||||
HLine3f plane = c->GetProjectionPlane();
|
||||
|
||||
@@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxRaytracerRepresentationTest) {
|
||||
grid.SetSpacing(Vector3f(1, 1, 1));
|
||||
grid.SetPosition(Vector3f(0, 0, 0));
|
||||
|
||||
Vtk::StructuredGrid v_grid(grid);
|
||||
Vtk::StructuredGrid v_grid(&grid);
|
||||
|
||||
// voxraytracer //
|
||||
VoxRaytracer rt(grid);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#include "Vtk/Math/vtkQuadMesh.h"
|
||||
#include "Vtk/Math/vtkQuadMesh.h"
|
||||
#include "Vtk/uLibVtkViewer.h"
|
||||
|
||||
@@ -39,10 +38,10 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) {
|
||||
mesh.AddPoint(Vector3f(1, 0, 0));
|
||||
mesh.AddPoint(Vector3f(1, 1, 0));
|
||||
mesh.AddPoint(Vector3f(0, 1, 0));
|
||||
|
||||
|
||||
mesh.AddQuad(Vector4i(0, 1, 2, 3));
|
||||
|
||||
Vtk::QuadMesh v_mesh(mesh);
|
||||
Vtk::QuadMesh v_mesh(&mesh);
|
||||
|
||||
Object::connect(&mesh, &QuadMesh::Updated, [&mesh]() {
|
||||
Vector3f points[4];
|
||||
@@ -50,8 +49,8 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) {
|
||||
points[1] = mesh.GetPoint(1);
|
||||
points[2] = mesh.GetPoint(2);
|
||||
points[3] = mesh.GetPoint(3);
|
||||
std::cout << "mesh updated: " << points[0] << " " << points[1]
|
||||
<< " " << points[2] << " " << points[3] << std::endl;
|
||||
std::cout << "mesh updated: " << points[0] << " " << points[1] << " "
|
||||
<< points[2] << " " << points[3] << std::endl;
|
||||
});
|
||||
|
||||
v_mesh.Update();
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#include "Vtk/Math/vtkStructuredGrid.h"
|
||||
#include "Vtk/Math/vtkStructuredGrid.h"
|
||||
#include "Vtk/uLibVtkViewer.h"
|
||||
|
||||
@@ -36,7 +35,7 @@ BOOST_AUTO_TEST_CASE(vtkStructuredGridTest) {
|
||||
StructuredGrid grid(Vector3i(10, 10, 100));
|
||||
grid.SetSpacing(Vector3f(3, 1, 1));
|
||||
|
||||
Vtk::StructuredGrid grid_viewer(grid);
|
||||
Vtk::StructuredGrid grid_viewer(&grid);
|
||||
|
||||
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
|
||||
Vtk::Viewer viewer;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#include "Vtk/Math/vtkTriangleMesh.h"
|
||||
#include "Vtk/Math/vtkTriangleMesh.h"
|
||||
#include "Vtk/uLibVtkViewer.h"
|
||||
|
||||
@@ -40,15 +39,16 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) {
|
||||
mesh.AddPoint(Vector3f(1, 0, 0));
|
||||
mesh.AddTriangle(Vector3i(0, 1, 2));
|
||||
|
||||
Vtk::TriangleMesh v_mesh(mesh);
|
||||
Vtk::TriangleMesh v_mesh(&mesh);
|
||||
|
||||
Object::connect(&mesh, &TriangleMesh::Updated, [&mesh]() {
|
||||
Vector3f points[3];
|
||||
points[0] = mesh.GetPoint(0);
|
||||
points[1] = mesh.GetPoint(1);
|
||||
points[2] = mesh.GetPoint(2);
|
||||
std::cout << "mesh updated: " << points[0].transpose() << " " << points[1].transpose()
|
||||
<< " " << points[2].transpose() << std::endl;
|
||||
std::cout << "mesh updated: " << points[0].transpose() << " "
|
||||
<< points[1].transpose() << " " << points[2].transpose()
|
||||
<< std::endl;
|
||||
});
|
||||
|
||||
v_mesh.Update();
|
||||
@@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) {
|
||||
BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction2) {
|
||||
TriangleMesh mesh;
|
||||
|
||||
Vtk::TriangleMesh v_mesh(mesh);
|
||||
Vtk::TriangleMesh v_mesh(&mesh);
|
||||
v_mesh.ReadFromStlFile("capelluzzo.stl");
|
||||
v_mesh.Update();
|
||||
|
||||
|
||||
@@ -9,134 +9,140 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
#include "Vtk/uLibVtkViewer.h"
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkCallbackCommand.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkRenderer.h>
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <vtkCallbackCommand.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkRenderer.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
|
||||
using namespace uLib;
|
||||
|
||||
struct AppState {
|
||||
std::vector<Vtk::VoxImage*> images;
|
||||
Vtk::Viewer* viewer;
|
||||
std::vector<Vtk::VoxImage *> images;
|
||||
Vtk::Viewer *viewer;
|
||||
};
|
||||
|
||||
void KeyPressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) {
|
||||
auto* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
|
||||
auto* state = static_cast<AppState*>(clientData);
|
||||
|
||||
std::string key = interactor->GetKeySym();
|
||||
if (key == "w") {
|
||||
std::cout << "--> Switching all images to Wireframe Box" << std::endl;
|
||||
for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Wireframe);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
}
|
||||
else if (key == "s") {
|
||||
std::cout << "--> Switching all images to Surface (Volume Rendering)" << std::endl;
|
||||
for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Surface);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
}
|
||||
else if (key >= "0" && key <= "5") {
|
||||
int preset = key[0] - '0';
|
||||
std::cout << "--> Switching all images to Rendering Preset " << preset << std::endl;
|
||||
for (auto* img : state->images) img->setShadingPreset(preset);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
}
|
||||
void KeyPressCallbackFunction(vtkObject *caller, long unsigned int eventId,
|
||||
void *clientData, void *callData) {
|
||||
auto *interactor = static_cast<vtkRenderWindowInteractor *>(caller);
|
||||
auto *state = static_cast<AppState *>(clientData);
|
||||
|
||||
std::string key = interactor->GetKeySym();
|
||||
if (key == "w") {
|
||||
std::cout << "--> Switching all images to Wireframe Box" << std::endl;
|
||||
for (auto *img : state->images)
|
||||
img->SetRepresentation(Vtk::Prop3D::Wireframe);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
} else if (key == "s") {
|
||||
std::cout << "--> Switching all images to Surface (Volume Rendering)"
|
||||
<< std::endl;
|
||||
for (auto *img : state->images)
|
||||
img->SetRepresentation(Vtk::Prop3D::Surface);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
} else if (key >= "0" && key <= "5") {
|
||||
int preset = key[0] - '0';
|
||||
std::cout << "--> Switching all images to Rendering Preset " << preset
|
||||
<< std::endl;
|
||||
for (auto *img : state->images)
|
||||
img->setShadingPreset(preset);
|
||||
state->viewer->GetRenderWindow()->Render();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
float factor = 1.0e6f;
|
||||
int main(int argc, char **argv) {
|
||||
float factor = 1.0e6f;
|
||||
|
||||
// --- Image 1: Spherical Shell ---
|
||||
Vector3i dims1(64, 64, 64);
|
||||
VoxImage<Voxel> img1(dims1);
|
||||
img1.SetSpacing(Vector3f(1.0, 1.0, 1.0));
|
||||
img1.SetPosition(Vector3f(-40, -32, -32));
|
||||
// --- Image 1: Spherical Shell ---
|
||||
Vector3i dims1(64, 64, 64);
|
||||
VoxImage<Voxel> img1(dims1);
|
||||
img1.SetSpacing(Vector3f(1.0, 1.0, 1.0));
|
||||
img1.SetPosition(Vector3f(-40, -32, -32));
|
||||
|
||||
for (int z = 0; z < dims1(2); ++z) {
|
||||
for (int y = 0; y < dims1(1); ++y) {
|
||||
for (int x = 0; x < dims1(0); ++x) {
|
||||
float dx = x - 32.0f;
|
||||
float dy = y - 32.0f;
|
||||
float dz = z - 32.0f;
|
||||
float dist = std::sqrt(dx*dx + dy*dy + dz*dz);
|
||||
Voxel v;
|
||||
if (dist < 25.0f && dist > 10.0f) {
|
||||
v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor;
|
||||
} else {
|
||||
v.Value = 0.0f;
|
||||
}
|
||||
img1[Vector3i(x, y, z)] = v;
|
||||
}
|
||||
for (int z = 0; z < dims1(2); ++z) {
|
||||
for (int y = 0; y < dims1(1); ++y) {
|
||||
for (int x = 0; x < dims1(0); ++x) {
|
||||
float dx = x - 32.0f;
|
||||
float dy = y - 32.0f;
|
||||
float dz = z - 32.0f;
|
||||
float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
Voxel v;
|
||||
if (dist < 25.0f && dist > 10.0f) {
|
||||
v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor;
|
||||
} else {
|
||||
v.Value = 0.0f;
|
||||
}
|
||||
img1[Vector3i(x, y, z)] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Image 2: Axes Gradient ---
|
||||
Vector3i dims2(64, 64, 64);
|
||||
VoxImage<Voxel> img2(dims2);
|
||||
img2.SetSpacing(Vector3f(1.0, 1.0, 1.0));
|
||||
img2.SetPosition(Vector3f(40, -32, -32));
|
||||
// --- Image 2: Axes Gradient ---
|
||||
Vector3i dims2(64, 64, 64);
|
||||
VoxImage<Voxel> img2(dims2);
|
||||
img2.SetSpacing(Vector3f(1.0, 1.0, 1.0));
|
||||
img2.SetPosition(Vector3f(40, -32, -32));
|
||||
|
||||
for (int z = 0; z < dims2(2); ++z) {
|
||||
for (int y = 0; y < dims2(1); ++y) {
|
||||
for (int x = 0; x < dims2(0); ++x) {
|
||||
Voxel v;
|
||||
// Linear gradient along X, Y, Z
|
||||
float val = (float(x)/dims2(0) + float(y)/dims2(1) + float(z)/dims2(2)) / 3.0f;
|
||||
v.Value = (40.0f * val) / factor;
|
||||
img2[Vector3i(x, y, z)] = v;
|
||||
}
|
||||
}
|
||||
for (int z = 0; z < dims2(2); ++z) {
|
||||
for (int y = 0; y < dims2(1); ++y) {
|
||||
for (int x = 0; x < dims2(0); ++x) {
|
||||
Voxel v;
|
||||
// Linear gradient along X, Y, Z
|
||||
float val =
|
||||
(float(x) / dims2(0) + float(y) / dims2(1) + float(z) / dims2(2)) /
|
||||
3.0f;
|
||||
v.Value = (40.0f * val) / factor;
|
||||
img2[Vector3i(x, y, z)] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vtk::VoxImage vtk_img1(img1);
|
||||
vtk_img1.setShadingPreset(0);
|
||||
Vtk::VoxImage vtk_img1(&img1);
|
||||
vtk_img1.setShadingPreset(0);
|
||||
|
||||
Vtk::VoxImage vtk_img2(img2);
|
||||
vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety
|
||||
Vtk::VoxImage vtk_img2(&img2);
|
||||
vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety
|
||||
|
||||
Vtk::Viewer viewer;
|
||||
viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1);
|
||||
viewer.AddProp3D(vtk_img1);
|
||||
viewer.AddProp3D(vtk_img2);
|
||||
|
||||
// Setup KeyPress Callback
|
||||
AppState state;
|
||||
state.images.push_back(&vtk_img1);
|
||||
state.images.push_back(&vtk_img2);
|
||||
state.viewer = &viewer;
|
||||
Vtk::Viewer viewer;
|
||||
viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1);
|
||||
viewer.AddProp3D(vtk_img1);
|
||||
viewer.AddProp3D(vtk_img2);
|
||||
|
||||
vtkSmartPointer<vtkCallbackCommand> keyCallback = vtkSmartPointer<vtkCallbackCommand>::New();
|
||||
keyCallback->SetCallback(KeyPressCallbackFunction);
|
||||
keyCallback->SetClientData(&state);
|
||||
viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback);
|
||||
// Setup KeyPress Callback
|
||||
AppState state;
|
||||
state.images.push_back(&vtk_img1);
|
||||
state.images.push_back(&vtk_img2);
|
||||
state.viewer = &viewer;
|
||||
|
||||
std::cout << "=========================================" << std::endl;
|
||||
std::cout << " VoxImage Interactive Viewer Test" << std::endl;
|
||||
std::cout << " [LEFT] Spherical Shell (MIP)" << std::endl;
|
||||
std::cout << " [RIGHT] Axes Gradient (Composite)" << std::endl;
|
||||
std::cout << "-----------------------------------------" << std::endl;
|
||||
std::cout << " Press [w] to show Wireframe Bounding Boxes" << std::endl;
|
||||
std::cout << " Press [s] to show Volume Rendering" << std::endl;
|
||||
std::cout << " Press [0..5] to switch Rendering Presets:" << std::endl;
|
||||
std::cout << " 0: MIP (Grayscale)" << std::endl;
|
||||
std::cout << " 1: Composite (Grayscale)" << std::endl;
|
||||
std::cout << " 2: Composite (Shaded)" << std::endl;
|
||||
std::cout << " 3: CT Bone/Tissue (Bone colors)" << std::endl;
|
||||
std::cout << " 4: MIP (Rainbow)" << std::endl;
|
||||
std::cout << " 5: Additive (Total path sum)" << std::endl;
|
||||
std::cout << " Press [q] to quit" << std::endl;
|
||||
std::cout << "=========================================" << std::endl;
|
||||
vtkSmartPointer<vtkCallbackCommand> keyCallback =
|
||||
vtkSmartPointer<vtkCallbackCommand>::New();
|
||||
keyCallback->SetCallback(KeyPressCallbackFunction);
|
||||
keyCallback->SetClientData(&state);
|
||||
viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback);
|
||||
|
||||
viewer.ZoomAuto();
|
||||
viewer.Start();
|
||||
std::cout << "=========================================" << std::endl;
|
||||
std::cout << " VoxImage Interactive Viewer Test" << std::endl;
|
||||
std::cout << " [LEFT] Spherical Shell (MIP)" << std::endl;
|
||||
std::cout << " [RIGHT] Axes Gradient (Composite)" << std::endl;
|
||||
std::cout << "-----------------------------------------" << std::endl;
|
||||
std::cout << " Press [w] to show Wireframe Bounding Boxes" << std::endl;
|
||||
std::cout << " Press [s] to show Volume Rendering" << std::endl;
|
||||
std::cout << " Press [0..5] to switch Rendering Presets:" << std::endl;
|
||||
std::cout << " 0: MIP (Grayscale)" << std::endl;
|
||||
std::cout << " 1: Composite (Grayscale)" << std::endl;
|
||||
std::cout << " 2: Composite (Shaded)" << std::endl;
|
||||
std::cout << " 3: CT Bone/Tissue (Bone colors)" << std::endl;
|
||||
std::cout << " 4: MIP (Rainbow)" << std::endl;
|
||||
std::cout << " 5: Additive (Total path sum)" << std::endl;
|
||||
std::cout << " Press [q] to quit" << std::endl;
|
||||
std::cout << "=========================================" << std::endl;
|
||||
|
||||
return 0;
|
||||
viewer.ZoomAuto();
|
||||
viewer.Start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
#include "Vtk/uLibVtkViewer.h"
|
||||
|
||||
@@ -46,7 +45,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxImageConstruction) {
|
||||
img.InitVoxels(zero);
|
||||
img[Vector3i(3, 3, 3)] = nonzero;
|
||||
|
||||
Vtk::VoxImage vtk_img(img);
|
||||
Vtk::VoxImage vtk_img(&img);
|
||||
vtk_img.SaveToXMLFile("test_vtkvoximage.vti");
|
||||
|
||||
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
|
||||
|
||||
@@ -31,14 +31,14 @@ namespace Vtk {
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
Assembly::Assembly(uLib::Assembly *content)
|
||||
: m_Content(content),
|
||||
: ObjectWrapper(content),
|
||||
m_ChildContext(nullptr),
|
||||
m_BBoxActor(nullptr),
|
||||
m_VtkAsm(nullptr),
|
||||
m_InUpdate(false) {
|
||||
this->InstallPipe();
|
||||
if (m_Content) {
|
||||
Object::connect(m_Content, &uLib::Assembly::Updated,
|
||||
if (this->m_model) {
|
||||
Object::connect(this->m_model.get(), &uLib::Assembly::Updated,
|
||||
this, &Assembly::Update);
|
||||
}
|
||||
}
|
||||
@@ -71,13 +71,13 @@ void Assembly::InstallPipe() {
|
||||
m_BBoxActor->GetProperty()->SetLineWidth(1.5);
|
||||
m_BBoxActor->GetProperty()->SetOpacity(0.6);
|
||||
m_BBoxActor->PickableOff();
|
||||
m_BBoxActor->SetVisibility(m_Content ? m_Content->GetShowBoundingBox() : false);
|
||||
m_BBoxActor->SetVisibility(this->m_model ? this->m_model->GetShowBoundingBox() : false);
|
||||
|
||||
m_VtkAsm->AddPart(m_BBoxActor);
|
||||
|
||||
// 3. Build a child-objects context (auto-creates prop3ds for each child)
|
||||
if (m_Content) {
|
||||
m_ChildContext = new ObjectsContext(m_Content);
|
||||
if (this->m_model) {
|
||||
m_ChildContext = new ObjectsContext(this->m_model);
|
||||
// Link the children context's assembly into our group assembly
|
||||
if (auto* childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) {
|
||||
m_VtkAsm->AddPart(childProp);
|
||||
@@ -93,10 +93,10 @@ void Assembly::Update() {
|
||||
if (m_InUpdate) return;
|
||||
m_InUpdate = true;
|
||||
|
||||
if (m_Content && m_VtkAsm) {
|
||||
if (this->m_model && m_VtkAsm) {
|
||||
// Apply world matrix from the assembly content
|
||||
vtkNew<vtkMatrix4x4> m;
|
||||
Matrix4fToVtk(m_Content->GetMatrix(), m);
|
||||
Matrix4fToVtk(this->m_model->GetMatrix(), m);
|
||||
m_VtkAsm->SetUserMatrix(m);
|
||||
m_VtkAsm->Modified();
|
||||
}
|
||||
@@ -110,33 +110,33 @@ void Assembly::Update() {
|
||||
|
||||
void Assembly::SyncFromVtk() {
|
||||
if (m_InUpdate) return;
|
||||
if (!m_Content || !m_VtkAsm) return;
|
||||
if (!this->m_model || !m_VtkAsm) return;
|
||||
|
||||
m_InUpdate = true;
|
||||
|
||||
// VTK -> Model: Update world matrix (accounting for model parents)
|
||||
if (vtkProp3D* proxy = this->GetProxyProp()) {
|
||||
m_Content->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix()));
|
||||
m_Content->FromMatrix(m_Content->GetMatrix());
|
||||
this->m_model->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix()));
|
||||
this->m_model->FromMatrix(this->m_model->GetMatrix());
|
||||
}
|
||||
|
||||
this->UpdateBoundingBox();
|
||||
if (m_ChildContext)
|
||||
m_ChildContext->SyncFromVtk();
|
||||
|
||||
m_Content->Updated(); // Notify change in model
|
||||
this->m_model->Updated(); // Notify change in model
|
||||
|
||||
m_InUpdate = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ //
|
||||
void Assembly::UpdateBoundingBox() {
|
||||
if (!m_Content || !m_BBoxActor) return;
|
||||
if (!this->m_model || !m_BBoxActor) return;
|
||||
|
||||
m_BBoxActor->SetVisibility(m_Content->GetShowBoundingBox());
|
||||
m_BBoxActor->SetVisibility(this->m_model->GetShowBoundingBox());
|
||||
|
||||
Vector3f bbMin, bbMax;
|
||||
m_Content->GetBoundingBox(bbMin, bbMax);
|
||||
this->m_model->GetBoundingBox(bbMin, bbMax);
|
||||
|
||||
// Avoid degenerate boxes
|
||||
Vector3f size = bbMax - bbMin;
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
#ifndef U_VTK_ASSEMBLY_H
|
||||
#define U_VTK_ASSEMBLY_H
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/Assembly.h"
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
|
||||
class vtkActor;
|
||||
class vtkAssembly; // VTK library forward declaration (must be before namespace)
|
||||
@@ -34,7 +35,7 @@ class ObjectsContext; // forward
|
||||
* the VTK library class vtkAssembly for grouping, but the two
|
||||
* are distinct.
|
||||
*/
|
||||
class Assembly : public Prop3D {
|
||||
class Assembly : public Prop3D, public uLib::ObjectWrapper<uLib::Assembly> {
|
||||
public:
|
||||
uLibTypeMacro(Assembly, Prop3D)
|
||||
|
||||
@@ -47,8 +48,8 @@ public:
|
||||
/** @brief Synchronizes the model from the VTK representation (VTK→model). */
|
||||
virtual void SyncFromVtk() override;
|
||||
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||
virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_Content; }
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_model.get(); }
|
||||
virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_model.get(); }
|
||||
|
||||
/**
|
||||
* @brief Returns the prop3d managing child objects.
|
||||
@@ -61,7 +62,6 @@ private:
|
||||
void UpdateBoundingBox();
|
||||
void InstallPipe();
|
||||
|
||||
uLib::Assembly *m_Content;
|
||||
ObjectsContext *m_ChildContext;
|
||||
vtkActor *m_BBoxActor;
|
||||
::vtkAssembly *m_VtkAsm; // VTK library assembly — NOT this class
|
||||
|
||||
@@ -66,9 +66,10 @@ struct ContainerBoxData {
|
||||
|
||||
|
||||
ContainerBox::ContainerBox(ContainerBox::Content *content)
|
||||
: d(new ContainerBoxData()), m_Content(content) {
|
||||
: d(new ContainerBoxData()), ObjectWrapper(content) {
|
||||
this->InstallPipe();
|
||||
d->m_UpdateSignal = Object::connect(m_Content, &uLib::Object::Updated, this, &ContainerBox::Update);
|
||||
d->m_UpdateSignal =
|
||||
Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &ContainerBox::Update);
|
||||
}
|
||||
|
||||
ContainerBox::~ContainerBox() {
|
||||
@@ -83,13 +84,13 @@ vtkPolyData *ContainerBox::GetPolyData() const {
|
||||
|
||||
void ContainerBox::Update() {
|
||||
RecursiveMutex::ScopedLock lock(this->m_UpdateMutex);
|
||||
if (!m_Content) return;
|
||||
if (!this->m_model) return;
|
||||
|
||||
vtkProp3D* prop = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (prop) {
|
||||
// Apply the full volume matrix (TRS * m_LocalT)
|
||||
vtkNew<vtkMatrix4x4> m;
|
||||
Matrix4fToVtk(m_Content->GetMatrix(), m);
|
||||
Matrix4fToVtk(this->m_model->GetMatrix(), m);
|
||||
prop->SetUserMatrix(m);
|
||||
prop->Modified();
|
||||
}
|
||||
@@ -104,7 +105,7 @@ void ContainerBox::Update() {
|
||||
|
||||
void ContainerBox::SyncFromVtk() {
|
||||
RecursiveMutex::ScopedLock lock(this->m_UpdateMutex);
|
||||
if (!m_Content) return;
|
||||
if (!this->m_model) return;
|
||||
|
||||
vtkProp3D* root = this->GetProxyProp();
|
||||
if (!root) return;
|
||||
@@ -114,11 +115,11 @@ void ContainerBox::SyncFromVtk() {
|
||||
Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
|
||||
|
||||
// Synchronize TRS property members from the updated local matrix
|
||||
m_Content->FromMatrix(vtkWorld);
|
||||
this->m_model->FromMatrix(vtkWorld);
|
||||
|
||||
// Since we modified the model, notify observers, but block the loop back to VTK
|
||||
// ConnectionBlock blocker(d->m_UpdateSignal);
|
||||
m_Content->Updated();
|
||||
this->m_model->Updated();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,9 +127,9 @@ void ContainerBox::SyncFromVtk() {
|
||||
|
||||
|
||||
void ContainerBox::InstallPipe() {
|
||||
if (!m_Content)
|
||||
if (!this->m_model)
|
||||
return;
|
||||
Content *c = m_Content;
|
||||
Content *c = this->m_model;
|
||||
|
||||
// CUBE
|
||||
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#ifndef U_VTKCONTAINERBOX_H
|
||||
#define U_VTKCONTAINERBOX_H
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/ContainerBox.h"
|
||||
#include "uLibVtkInterface.h"
|
||||
#include "vtkPolydata.h"
|
||||
@@ -37,11 +38,13 @@ namespace Vtk {
|
||||
|
||||
struct ContainerBoxData;
|
||||
|
||||
class ContainerBox : public Prop3D, public Polydata {
|
||||
|
||||
class ContainerBox : public Prop3D,
|
||||
public Polydata,
|
||||
public uLib::ObjectWrapper<uLib::ContainerBox> {
|
||||
|
||||
uLibTypeMacro(ContainerBox, Prop3D, Polydata)
|
||||
typedef uLib::ContainerBox Content;
|
||||
|
||||
|
||||
public:
|
||||
ContainerBox(Content *content);
|
||||
~ContainerBox();
|
||||
@@ -58,14 +61,15 @@ public:
|
||||
*/
|
||||
virtual void SyncFromVtk() override;
|
||||
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||
virtual uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void InstallPipe();
|
||||
|
||||
struct ContainerBoxData *d;
|
||||
uLib::ContainerBox *m_Content;
|
||||
|
||||
|
||||
ULIB_DECLARE_PROPERTIES(ContainerBox)
|
||||
};
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
Cylinder::Cylinder(Cylinder::Content *content)
|
||||
: m_Content(content), m_Actor(nullptr), m_VtkAsm(nullptr) {
|
||||
: ObjectWrapper(content), m_Actor(nullptr), m_VtkAsm(nullptr) {
|
||||
this->InstallPipe();
|
||||
m_UpdateSignal = Object::connect(m_Content, &uLib::Object::Updated, this, &Cylinder::Update);
|
||||
m_UpdateSignal = Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &Cylinder::Update);
|
||||
}
|
||||
|
||||
Cylinder::~Cylinder() {
|
||||
@@ -49,14 +49,14 @@ Cylinder::~Cylinder() {
|
||||
}
|
||||
|
||||
void Cylinder::Update() {
|
||||
if (!m_Content)
|
||||
if (!this->m_model)
|
||||
return;
|
||||
|
||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (root) {
|
||||
// 1. Placement handled specifically from content (use TRS GetMatrix, not World)
|
||||
vtkNew<vtkMatrix4x4> m;
|
||||
Matrix4fToVtk(m_Content->GetMatrix(), m);
|
||||
Matrix4fToVtk(this->m_model->GetMatrix(), m);
|
||||
root->SetUserMatrix(m);
|
||||
|
||||
// 2. Shape-local properties (Radius, Height, Axis alignment) go to the internal actor
|
||||
@@ -68,10 +68,10 @@ void Cylinder::Update() {
|
||||
|
||||
// Initial source is centered Y-cylinder (Radial XZ [-1,1], Height Y [-0.5, 0.5])
|
||||
// Apply Radius and Height scaling
|
||||
alignment->Scale(m_Content->GetRadius(), m_Content->GetHeight(), m_Content->GetRadius());
|
||||
alignment->Scale(this->m_model->GetRadius(), this->m_model->GetHeight(), this->m_model->GetRadius());
|
||||
|
||||
// Apply Axis alignment
|
||||
int axis = m_Content->GetAxis();
|
||||
int axis = this->m_model->GetAxis();
|
||||
if (axis == 0) alignment->RotateZ(-90); // Y -> X
|
||||
else if (axis == 1) ; // Y -> Y (identity)
|
||||
else if (axis == 2) alignment->RotateX(90); // Y -> Z
|
||||
@@ -86,7 +86,7 @@ void Cylinder::Update() {
|
||||
}
|
||||
|
||||
void Cylinder::SyncFromVtk() {
|
||||
if (!m_Content) return;
|
||||
if (!this->m_model) return;
|
||||
|
||||
vtkProp3D* root = this->GetProxyProp();
|
||||
if (!root) return;
|
||||
@@ -96,12 +96,12 @@ void Cylinder::SyncFromVtk() {
|
||||
Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
|
||||
|
||||
// Directly sync model from the world matrix
|
||||
m_Content->FromMatrix(vtkWorld);
|
||||
m_Content->Updated();
|
||||
this->m_model->FromMatrix(vtkWorld);
|
||||
this->m_model->Updated();
|
||||
}
|
||||
|
||||
void Cylinder::InstallPipe() {
|
||||
if (!m_Content)
|
||||
if (!this->m_model)
|
||||
return;
|
||||
|
||||
m_VtkAsm = ::vtkAssembly::New();
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#ifndef U_VTKCYLINDER_H
|
||||
#define U_VTKCYLINDER_H
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/Cylinder.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include <vtkActor.h>
|
||||
@@ -41,7 +42,7 @@ namespace Vtk {
|
||||
* mathematical state of a Cylinder object. It manages the alignment
|
||||
* between VTK's Y-centered cylinder and uLib's Z-based coordinate system.
|
||||
*/
|
||||
class Cylinder : public Prop3D {
|
||||
class Cylinder : public Prop3D, public uLib::ObjectWrapper<uLib::Cylinder> {
|
||||
typedef uLib::Cylinder Content;
|
||||
|
||||
public:
|
||||
@@ -54,7 +55,9 @@ public:
|
||||
/** Synchronizes the uLib model matrix with the VTK actor specifically for gizmo interactions */
|
||||
virtual void SyncFromVtk() override;
|
||||
|
||||
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||
virtual uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Sets up the VTK visualization pipeline */
|
||||
@@ -62,7 +65,6 @@ protected:
|
||||
|
||||
vtkActor *m_Actor;
|
||||
::vtkAssembly *m_VtkAsm;
|
||||
Content *m_Content;
|
||||
uLib::Connection m_UpdateSignal;
|
||||
};
|
||||
|
||||
|
||||
@@ -58,22 +58,22 @@ void QuadMesh::vtk2uLib_update() {
|
||||
<< "number of quads = " << number_of_quads << "\n"
|
||||
<< "//////\n";
|
||||
|
||||
m_content.Points().clear();
|
||||
this->m_model->Points().clear();
|
||||
for (int i = 0; i < number_of_points; ++i) {
|
||||
double *point = m_Poly->GetPoint(i);
|
||||
m_content.Points().push_back(Vector3f(point[0], point[1], point[2]));
|
||||
this->m_model->Points().push_back(Vector3f(point[0], point[1], point[2]));
|
||||
}
|
||||
|
||||
m_content.Quads().resize(number_of_quads);
|
||||
this->m_model->Quads().resize(number_of_quads);
|
||||
m_Poly->GetPolys()->InitTraversal();
|
||||
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
|
||||
for (int i = 0; i < number_of_quads; ++i) {
|
||||
m_Poly->GetPolys()->GetNextCell(idList);
|
||||
if (idList->GetNumberOfIds() == 4) {
|
||||
m_content.Quads()[i](0) = idList->GetId(0);
|
||||
m_content.Quads()[i](1) = idList->GetId(1);
|
||||
m_content.Quads()[i](2) = idList->GetId(2);
|
||||
m_content.Quads()[i](3) = idList->GetId(3);
|
||||
this->m_model->Quads()[i](0) = idList->GetId(0);
|
||||
this->m_model->Quads()[i](1) = idList->GetId(1);
|
||||
this->m_model->Quads()[i](2) = idList->GetId(2);
|
||||
this->m_model->Quads()[i](3) = idList->GetId(3);
|
||||
}
|
||||
}
|
||||
m_Poly->Modified();
|
||||
@@ -81,23 +81,23 @@ void QuadMesh::vtk2uLib_update() {
|
||||
}
|
||||
|
||||
void QuadMesh::uLib2vtk_update() {
|
||||
vtkIdType number_of_points = m_content.Points().size();
|
||||
vtkIdType number_of_quads = m_content.Quads().size();
|
||||
vtkIdType number_of_points = this->m_model->Points().size();
|
||||
vtkIdType number_of_quads = this->m_model->Quads().size();
|
||||
|
||||
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
|
||||
points->SetNumberOfPoints(number_of_points);
|
||||
for (vtkIdType i = 0; i < number_of_points; i++) {
|
||||
Vector3f p = m_content.Points().at(i);
|
||||
Vector3f p = this->m_model->Points().at(i);
|
||||
points->SetPoint(i, p(0), p(1), p(2));
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
|
||||
for (vtkIdType i = 0; i < number_of_quads; i++) {
|
||||
vtkIdType a, b, c, d;
|
||||
a = m_content.Quads().at(i)(0);
|
||||
b = m_content.Quads().at(i)(1);
|
||||
c = m_content.Quads().at(i)(2);
|
||||
d = m_content.Quads().at(i)(3);
|
||||
a = this->m_model->Quads().at(i)(0);
|
||||
b = this->m_model->Quads().at(i)(1);
|
||||
c = this->m_model->Quads().at(i)(2);
|
||||
d = this->m_model->Quads().at(i)(3);
|
||||
polys->InsertNextCell(4);
|
||||
polys->InsertCellPoint(a);
|
||||
polys->InsertCellPoint(b);
|
||||
@@ -118,7 +118,7 @@ void QuadMesh::contentUpdate() {
|
||||
vmat = mat;
|
||||
}
|
||||
|
||||
Matrix4f transform = m_content.GetWorldMatrix();
|
||||
Matrix4f transform = this->m_model->GetWorldMatrix();
|
||||
Matrix4fToVtk(transform, vmat);
|
||||
|
||||
uLib2vtk_update();
|
||||
@@ -133,30 +133,30 @@ void QuadMesh::Update() {
|
||||
if (!vmat) return;
|
||||
|
||||
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||
m_content.SetMatrix(transform);
|
||||
m_content.Updated();
|
||||
this->m_model->SetMatrix(transform);
|
||||
this->m_model->Updated();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
QuadMesh::QuadMesh(QuadMesh::Content &content)
|
||||
: m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
|
||||
QuadMesh::QuadMesh(QuadMesh::Content *content)
|
||||
: ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper =
|
||||
vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputData(m_Poly);
|
||||
m_Actor->SetMapper(mapper);
|
||||
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
Matrix4fToVtk(m_content.GetWorldMatrix(), vmat);
|
||||
Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
|
||||
m_Actor->SetUserMatrix(vmat);
|
||||
|
||||
this->SetProp(m_Actor);
|
||||
Object::connect(&m_content, &Content::Updated, this, &QuadMesh::contentUpdate);
|
||||
Object::connect(this->m_model.get(), &Content::Updated, this, &QuadMesh::contentUpdate);
|
||||
this->contentUpdate();
|
||||
}
|
||||
|
||||
QuadMesh::~QuadMesh() {
|
||||
Object::disconnect(&m_content, &Content::Updated, this, &QuadMesh::contentUpdate);
|
||||
Object::disconnect(this->m_model.get(), &Content::Updated, this, &QuadMesh::contentUpdate);
|
||||
m_Poly->Delete();
|
||||
m_Actor->Delete();
|
||||
}
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
#ifndef VTKQUADMESH_H
|
||||
#define VTKQUADMESH_H
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/QuadMesh.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
|
||||
class vtkPolyData;
|
||||
class vtkActor;
|
||||
@@ -36,11 +37,13 @@ class vtkActor;
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
class QuadMesh : public Prop3D, public Polydata {
|
||||
class QuadMesh : public Prop3D,
|
||||
public Polydata,
|
||||
public uLib::ObjectWrapper<uLib::QuadMesh> {
|
||||
typedef uLib::QuadMesh Content;
|
||||
|
||||
public:
|
||||
QuadMesh(Content &content);
|
||||
QuadMesh(Content *content);
|
||||
~QuadMesh();
|
||||
|
||||
void ReadFromFile(const char *filename);
|
||||
@@ -56,12 +59,15 @@ public:
|
||||
virtual void contentUpdate();
|
||||
|
||||
virtual void Update();
|
||||
uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
private:
|
||||
void vtk2uLib_update();
|
||||
void uLib2vtk_update();
|
||||
|
||||
uLib::QuadMesh &m_content;
|
||||
// ObjectWrapper provides m_model
|
||||
vtkPolyData *m_Poly;
|
||||
vtkActor *m_Actor;
|
||||
};
|
||||
|
||||
@@ -39,8 +39,8 @@ namespace Vtk {
|
||||
////// VTK STRUCTURED GRID /////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StructuredGrid::StructuredGrid(Content &content)
|
||||
: m_Content(&content), m_Actor(vtkActor::New()),
|
||||
StructuredGrid::StructuredGrid(Content *content)
|
||||
: ObjectWrapper(content), m_Actor(vtkActor::New()),
|
||||
m_Transform(vtkTransform::New()) {
|
||||
|
||||
this->InstallPipe();
|
||||
@@ -54,10 +54,10 @@ StructuredGrid::~StructuredGrid() {
|
||||
void StructuredGrid::SetTransform(vtkTransform *t) {
|
||||
vtkMatrix4x4 *vmat = t->GetMatrix();
|
||||
Matrix4f mat = VtkToMatrix4f(vmat);
|
||||
m_Content->SetMatrix(mat);
|
||||
this->m_model->SetMatrix(mat);
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> vmat2 = vtkSmartPointer<vtkMatrix4x4>::New();
|
||||
mat = m_Content->GetWorldMatrix();
|
||||
mat = this->m_model->GetWorldMatrix();
|
||||
Matrix4fToVtk(mat, vmat2);
|
||||
m_Transform->SetMatrix(vmat2);
|
||||
m_Transform->Update();
|
||||
@@ -65,7 +65,7 @@ void StructuredGrid::SetTransform(vtkTransform *t) {
|
||||
}
|
||||
|
||||
void StructuredGrid::Update() {
|
||||
if (!m_Content) return;
|
||||
if (!this->m_model) return;
|
||||
|
||||
vtkProp3D* actor = vtkProp3D::SafeDownCast(this->GetProp());
|
||||
if (!actor) return;
|
||||
@@ -76,20 +76,20 @@ void StructuredGrid::Update() {
|
||||
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||
|
||||
// Update uLib model's affine transform
|
||||
if (m_Content->GetParent()) {
|
||||
Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform;
|
||||
m_Content->SetMatrix(localT);
|
||||
if (this->m_model->GetParent()) {
|
||||
Matrix4f localT = this->m_model->GetParent()->GetWorldMatrix().inverse() * transform;
|
||||
this->m_model->SetMatrix(localT);
|
||||
} else {
|
||||
m_Content->SetMatrix(transform);
|
||||
this->m_model->SetMatrix(transform);
|
||||
}
|
||||
|
||||
m_Content->Updated(); // Notify others (like raytracer)
|
||||
this->m_model->Updated(); // Notify others (like raytracer)
|
||||
}
|
||||
|
||||
void StructuredGrid::InstallPipe() {
|
||||
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
|
||||
|
||||
Vector3i dims = m_Content->GetDims();
|
||||
Vector3i dims = this->m_model->GetDims();
|
||||
cube->SetBounds(0, dims(0), 0, dims(1), 0, dims(2));
|
||||
cube->Update();
|
||||
|
||||
@@ -104,7 +104,7 @@ void StructuredGrid::InstallPipe() {
|
||||
m_Actor->GetProperty()->SetAmbient(0.7);
|
||||
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
Matrix4fToVtk(m_Content->GetWorldMatrix(), vmat);
|
||||
Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
|
||||
m_Actor->SetUserMatrix(vmat);
|
||||
|
||||
this->SetProp(m_Actor);
|
||||
|
||||
@@ -41,28 +41,32 @@
|
||||
|
||||
#include "Vtk/Math/vtkDense.h"
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/StructuredGrid.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
class StructuredGrid : public Prop3D {
|
||||
class StructuredGrid : public Prop3D,
|
||||
public uLib::ObjectWrapper<uLib::StructuredGrid> {
|
||||
typedef uLib::StructuredGrid Content;
|
||||
|
||||
public:
|
||||
StructuredGrid(Content &content);
|
||||
StructuredGrid(Content *content);
|
||||
~StructuredGrid();
|
||||
|
||||
void SetTransform(class vtkTransform *t);
|
||||
|
||||
virtual void Update() override;
|
||||
uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
private:
|
||||
void InstallPipe();
|
||||
|
||||
vtkActor *m_Actor;
|
||||
uLib::StructuredGrid *m_Content;
|
||||
vtkTransform *m_Transform;
|
||||
};
|
||||
|
||||
|
||||
@@ -58,42 +58,42 @@ void TriangleMesh::vtk2uLib_update() {
|
||||
<< "number of polys = " << number_of_triangles << "\n"
|
||||
<< "//////\n";
|
||||
|
||||
m_content.Points().clear();
|
||||
this->m_model->Points().clear();
|
||||
for (int i = 0; i < number_of_points; ++i) {
|
||||
double *point = m_Poly->GetPoint(i);
|
||||
m_content.Points().push_back(Vector3f(point[0], point[1], point[2]));
|
||||
this->m_model->Points().push_back(Vector3f(point[0], point[1], point[2]));
|
||||
}
|
||||
|
||||
m_content.Triangles().resize(number_of_triangles);
|
||||
this->m_model->Triangles().resize(number_of_triangles);
|
||||
m_Poly->GetPolys()->InitTraversal();
|
||||
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
|
||||
for (int i = 0; i < number_of_triangles; ++i) {
|
||||
m_Poly->GetPolys()->GetNextCell(idList);
|
||||
m_content.Triangles()[i](0) = idList->GetId(0);
|
||||
m_content.Triangles()[i](1) = idList->GetId(1);
|
||||
m_content.Triangles()[i](2) = idList->GetId(2);
|
||||
this->m_model->Triangles()[i](0) = idList->GetId(0);
|
||||
this->m_model->Triangles()[i](1) = idList->GetId(1);
|
||||
this->m_model->Triangles()[i](2) = idList->GetId(2);
|
||||
}
|
||||
m_Poly->Modified();
|
||||
m_Actor->GetMapper()->Update();
|
||||
}
|
||||
|
||||
void TriangleMesh::uLib2vtk_update() {
|
||||
vtkIdType number_of_points = m_content.Points().size();
|
||||
vtkIdType number_of_triangles = m_content.Triangles().size();
|
||||
vtkIdType number_of_points = this->m_model->Points().size();
|
||||
vtkIdType number_of_triangles = this->m_model->Triangles().size();
|
||||
|
||||
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
|
||||
points->SetNumberOfPoints(number_of_points);
|
||||
for (vtkIdType i = 0; i < number_of_points; i++) {
|
||||
Vector3f p = m_content.Points().at(i);
|
||||
Vector3f p = this->m_model->Points().at(i);
|
||||
points->SetPoint(i, p(0), p(1), p(2));
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
|
||||
for (vtkIdType i = 0; i < number_of_triangles; i++) {
|
||||
vtkIdType a, b, c;
|
||||
a = m_content.Triangles().at(i)(0);
|
||||
b = m_content.Triangles().at(i)(1);
|
||||
c = m_content.Triangles().at(i)(2);
|
||||
a = this->m_model->Triangles().at(i)(0);
|
||||
b = this->m_model->Triangles().at(i)(1);
|
||||
c = this->m_model->Triangles().at(i)(2);
|
||||
polys->InsertNextCell(3);
|
||||
polys->InsertCellPoint(a);
|
||||
polys->InsertCellPoint(b);
|
||||
@@ -113,7 +113,7 @@ void TriangleMesh::contentUpdate() {
|
||||
vmat = mat;
|
||||
}
|
||||
|
||||
Matrix4f transform = m_content.GetWorldMatrix();
|
||||
Matrix4f transform = this->m_model->GetWorldMatrix();
|
||||
Matrix4fToVtk(transform, vmat);
|
||||
|
||||
uLib2vtk_update();
|
||||
@@ -128,30 +128,30 @@ void TriangleMesh::Update() {
|
||||
if (!vmat) return;
|
||||
|
||||
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||
m_content.SetMatrix(transform);
|
||||
m_content.Updated();
|
||||
this->m_model->SetMatrix(transform);
|
||||
this->m_model->Updated();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
TriangleMesh::TriangleMesh(TriangleMesh::Content &content)
|
||||
: m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
|
||||
TriangleMesh::TriangleMesh(TriangleMesh::Content *content)
|
||||
: ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper =
|
||||
vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputData(m_Poly);
|
||||
m_Actor->SetMapper(mapper);
|
||||
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
Matrix4fToVtk(m_content.GetWorldMatrix(), vmat);
|
||||
Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
|
||||
m_Actor->SetUserMatrix(vmat);
|
||||
|
||||
this->SetProp(m_Actor);
|
||||
Object::connect(&m_content, &Content::Updated, this, &TriangleMesh::contentUpdate);
|
||||
Object::connect(this->m_model.get(), &Content::Updated, this, &TriangleMesh::contentUpdate);
|
||||
this->contentUpdate();
|
||||
}
|
||||
|
||||
TriangleMesh::~TriangleMesh() {
|
||||
Object::disconnect(&m_content, &Content::Updated, this, &TriangleMesh::contentUpdate);
|
||||
Object::disconnect(this->m_model.get(), &Content::Updated, this, &TriangleMesh::contentUpdate);
|
||||
m_Poly->Delete();
|
||||
m_Actor->Delete();
|
||||
}
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
#ifndef VTKTRIANGLEMESH_H
|
||||
#define VTKTRIANGLEMESH_H
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Math/TriangleMesh.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Vtk/Math/vtkPolydata.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
|
||||
class vtkPolyData;
|
||||
class vtkActor;
|
||||
@@ -36,11 +37,13 @@ class vtkActor;
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
class TriangleMesh : public Prop3D, public Polydata {
|
||||
class TriangleMesh : public Prop3D,
|
||||
public Polydata,
|
||||
public uLib::ObjectWrapper<uLib::TriangleMesh> {
|
||||
typedef uLib::TriangleMesh Content;
|
||||
|
||||
public:
|
||||
TriangleMesh(Content &content);
|
||||
TriangleMesh(Content *content);
|
||||
~TriangleMesh();
|
||||
|
||||
void ReadFromFile(const char *filename);
|
||||
@@ -56,12 +59,15 @@ public:
|
||||
virtual void contentUpdate();
|
||||
|
||||
virtual void Update();
|
||||
uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
private:
|
||||
void vtk2uLib_update();
|
||||
void uLib2vtk_update();
|
||||
|
||||
uLib::TriangleMesh &m_content;
|
||||
// ObjectWrapper provides m_model
|
||||
vtkPolyData *m_Poly;
|
||||
vtkActor *m_Actor;
|
||||
};
|
||||
|
||||
@@ -61,13 +61,13 @@ namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
void VoxImage::UpdateFromContent() {
|
||||
Vector3i ev_dims = m_Content.GetDims();
|
||||
Vector3i ev_dims = this->m_model->GetDims();
|
||||
m_Image->SetDimensions(ev_dims.data());
|
||||
|
||||
Vector3f ev_spacing = m_Content.GetSpacing();
|
||||
Vector3f ev_spacing = this->m_model->GetSpacing();
|
||||
m_Image->SetSpacing(ev_spacing(0), ev_spacing(1), ev_spacing(2));
|
||||
|
||||
Vector3f ev_pos = m_Content.GetPosition();
|
||||
Vector3f ev_pos = this->m_model->GetPosition();
|
||||
m_Image->SetOrigin(ev_pos(0), ev_pos(1), ev_pos(2));
|
||||
|
||||
vtkFloatArray *array =
|
||||
@@ -78,14 +78,14 @@ void VoxImage::UpdateFromContent() {
|
||||
array->Delete();
|
||||
}
|
||||
|
||||
array->SetNumberOfTuples(m_Content.GetDims().prod());
|
||||
array->SetNumberOfTuples(this->m_model->GetDims().prod());
|
||||
Vector3i index(0, 0, 0);
|
||||
int i = 0;
|
||||
for (int zv = 0; zv < ev_dims(2); ++zv) {
|
||||
for (int yv = 0; yv < ev_dims(1); ++yv) {
|
||||
for (int xv = 0; xv < ev_dims(0); ++xv) {
|
||||
index << xv, yv, zv;
|
||||
array->SetValue(i++, m_Content.GetValue(index));
|
||||
array->SetValue(i++, this->m_model->GetValue(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,13 +94,13 @@ void VoxImage::UpdateFromContent() {
|
||||
void VoxImage::UpdateToContent() {
|
||||
int *ext = m_Image->GetExtent();
|
||||
int dims[3] = {ext[1] - ext[0] + 1, ext[3] - ext[2] + 1, ext[5] - ext[4] + 1};
|
||||
m_Content.SetDims(Vector3i(dims[0], dims[1], dims[2]));
|
||||
this->m_model->SetDims(Vector3i(dims[0], dims[1], dims[2]));
|
||||
|
||||
double *spacing = m_Image->GetSpacing();
|
||||
m_Content.SetSpacing(Vector3f(spacing[0], spacing[1], spacing[2]));
|
||||
this->m_model->SetSpacing(Vector3f(spacing[0], spacing[1], spacing[2]));
|
||||
|
||||
double *pos = m_Image->GetOrigin();
|
||||
m_Content.SetPosition(Vector3f(pos[0], pos[1], pos[2]));
|
||||
this->m_model->SetPosition(Vector3f(pos[0], pos[1], pos[2]));
|
||||
|
||||
vtkFloatArray *array =
|
||||
vtkFloatArray::SafeDownCast(m_Image->GetPointData()->GetScalars());
|
||||
@@ -111,7 +111,7 @@ void VoxImage::UpdateToContent() {
|
||||
for (int yv = 0; yv < dims[1]; ++yv) {
|
||||
for (int xv = 0; xv < dims[0]; ++xv) {
|
||||
index << xv, yv, zv;
|
||||
m_Content.SetValue(index, array->GetValue(i++));
|
||||
this->m_model->SetValue(index, array->GetValue(i++));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,8 +124,8 @@ void VoxImage::UpdateToContent() {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// VTK VOXIMAGE
|
||||
|
||||
VoxImage::VoxImage(Content &content)
|
||||
: m_Content(content), m_Actor(vtkVolume::New()),
|
||||
VoxImage::VoxImage(Content *content)
|
||||
: ObjectWrapper(content), m_Actor(vtkVolume::New()),
|
||||
m_Asm(vtkAssembly::New()),
|
||||
m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()),
|
||||
m_OutlineActor(vtkActor::New()),
|
||||
@@ -134,7 +134,7 @@ VoxImage::VoxImage(Content &content)
|
||||
// Transfer functions
|
||||
m_ColorFun = vtkColorTransferFunction::New();
|
||||
m_OpacityFun = vtkPiecewiseFunction::New();
|
||||
m_UpdateConnection = Object::connect(&m_Content, &uLib::Object::Updated, this, &VoxImage::Update);
|
||||
m_UpdateConnection = Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &VoxImage::Update);
|
||||
|
||||
UpdateFromContent();
|
||||
InstallPipe();
|
||||
@@ -314,8 +314,8 @@ void VoxImage::SyncFromVtk() {
|
||||
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();
|
||||
this->m_model->FromMatrix(vtkLocal); // * this->m_model->GetLocalMatrix().inverse());
|
||||
this->m_model->Updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,11 +323,11 @@ void VoxImage::SyncFromVtk() {
|
||||
void VoxImage::Update() {
|
||||
if (auto *root = vtkProp3D::SafeDownCast(this->GetProp())) {
|
||||
vtkNew<vtkMatrix4x4> m;
|
||||
Matrix4fToVtk(m_Content.GetMatrix(), m); // * m_Content.GetLocalMatrix(), m);
|
||||
Matrix4fToVtk(this->m_model->GetMatrix(), m); // * this->m_model->GetLocalMatrix(), m);
|
||||
root->SetUserMatrix(m);
|
||||
root->Modified();
|
||||
// std::cout << "[VoxImage::Update] Set Proxy UserMatrix:" << std::endl;
|
||||
// std::cout << m_Content.GetMatrix() << std::endl;
|
||||
// std::cout << this->m_model->GetMatrix() << std::endl;
|
||||
}
|
||||
setShadingPreset(m_ShadingPreset);
|
||||
m_Actor->Update();
|
||||
|
||||
@@ -26,15 +26,16 @@
|
||||
#ifndef U_VTKVOXIMAGE_H
|
||||
#define U_VTKVOXIMAGE_H
|
||||
|
||||
#include <vtkAssembly.h>
|
||||
#include <vtkCubeSource.h>
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkVolume.h>
|
||||
#include <vtkXMLImageDataReader.h>
|
||||
#include <vtkXMLImageDataWriter.h>
|
||||
#include <vtkAssembly.h>
|
||||
|
||||
#include <Math/VoxImage.h>
|
||||
|
||||
#include "Core/ObjectFactory.h"
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
|
||||
class vtkImageData;
|
||||
@@ -45,18 +46,21 @@ class vtkPiecewiseFunction;
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
class VoxImage : public Prop3D {
|
||||
class VoxImage : public Prop3D,
|
||||
public uLib::ObjectWrapper<uLib::Abstract::VoxImage> {
|
||||
public:
|
||||
typedef Abstract::VoxImage Content;
|
||||
|
||||
VoxImage(Content &content);
|
||||
VoxImage(Content *content);
|
||||
|
||||
~VoxImage();
|
||||
|
||||
void UpdateFromContent();
|
||||
|
||||
void UpdateToContent();
|
||||
uLib::Object* GetContent() const override { return (uLib::Object*)&m_Content; }
|
||||
uLib::Object *GetContent() const override {
|
||||
return (uLib::Object *)m_model.get();
|
||||
}
|
||||
|
||||
vtkProp3D *GetProp() override { return m_Asm; }
|
||||
|
||||
@@ -74,7 +78,8 @@ public:
|
||||
|
||||
void Update() override;
|
||||
void SyncFromVtk() override;
|
||||
void serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version = 0) override;
|
||||
void serialize_display(uLib::Archive::display_properties_archive &ar,
|
||||
const unsigned int version = 0) override;
|
||||
|
||||
protected:
|
||||
void InstallPipe();
|
||||
@@ -90,7 +95,7 @@ private:
|
||||
vtkXMLImageDataReader *m_Reader;
|
||||
vtkXMLImageDataWriter *m_Writer;
|
||||
|
||||
VoxImage::Content &m_Content;
|
||||
// ObjectWrapper provides m_model
|
||||
|
||||
float m_Window;
|
||||
float m_Level;
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
#include "vtkObjectsContext.h"
|
||||
#include "Vtk/Math/vtkAssembly.h"
|
||||
#include "Vtk/Math/vtkContainerBox.h"
|
||||
#include "Vtk/Math/vtkCylinder.h"
|
||||
#include "Vtk/Math/vtkAssembly.h"
|
||||
#include "Vtk/Math/vtkVoxImage.h"
|
||||
|
||||
#include "Vtk/HEP/Detectors/vtkDetectorChamber.h"
|
||||
#include "Vtk/HEP/Geant/vtkBoxSolid.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vtkAssembly.h>
|
||||
#include <vtkPropCollection.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
#include "Math/ContainerBox.h"
|
||||
#include "Math/Cylinder.h"
|
||||
#include "Math/Assembly.h"
|
||||
#include "Math/VoxImage.h"
|
||||
#include "HEP/Detectors/DetectorChamber.h"
|
||||
#include "HEP/Geant/Solid.h"
|
||||
|
||||
#include "Math/Assembly.h"
|
||||
#include "Math/ContainerBox.h"
|
||||
#include "Math/Cylinder.h"
|
||||
#include "Math/VoxImage.h"
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
@@ -27,35 +26,41 @@ ObjectsContext::ObjectsContext(uLib::ObjectsContext *context)
|
||||
: m_Context(context), m_Assembly(::vtkAssembly::New()) {
|
||||
this->SetProp(m_Assembly);
|
||||
if (m_Context) {
|
||||
Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this, &ObjectsContext::OnObjectAdded);
|
||||
Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this, &ObjectsContext::OnObjectRemoved);
|
||||
Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this,
|
||||
&ObjectsContext::OnObjectAdded);
|
||||
Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this,
|
||||
&ObjectsContext::OnObjectRemoved);
|
||||
this->Synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
ObjectsContext::~ObjectsContext() {
|
||||
for (auto const& [obj, prop3d] : m_Prop3Ds) {
|
||||
for (auto const &[obj, prop3d] : m_Prop3Ds) {
|
||||
delete prop3d;
|
||||
}
|
||||
m_Assembly->Delete();
|
||||
}
|
||||
|
||||
void ObjectsContext::Synchronize() {
|
||||
if (!m_Context) return;
|
||||
if (!m_Context)
|
||||
return;
|
||||
|
||||
// 1. Identify objects to add and remove
|
||||
const auto& objects = m_Context->GetObjects();
|
||||
std::map<uLib::Object*, bool> currentObjects;
|
||||
for (auto obj : objects) currentObjects[obj] = true;
|
||||
const auto &objects = m_Context->GetObjects();
|
||||
std::map<uLib::Object *, bool> currentObjects;
|
||||
for (auto obj : objects)
|
||||
currentObjects[obj] = true;
|
||||
|
||||
// Remove Prop3Ds for objects no longer in context
|
||||
for (auto it = m_Prop3Ds.begin(); it != m_Prop3Ds.end(); ) {
|
||||
for (auto it = m_Prop3Ds.begin(); it != m_Prop3Ds.end();) {
|
||||
if (currentObjects.find(it->first) == currentObjects.end()) {
|
||||
it->second->DisconnectRenderer(nullptr); // If we have a ref to a renderer we should disconnect but Prop3D doesn't store it easily
|
||||
it->second->DisconnectRenderer(
|
||||
nullptr); // If we have a ref to a renderer we should disconnect but
|
||||
// Prop3D doesn't store it easily
|
||||
// Actually Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer.
|
||||
// For now we just remove from assembly
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||
m_Assembly->RemovePart(p3d);
|
||||
if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||
m_Assembly->RemovePart(p3d);
|
||||
this->Prop3DRemoved(it->second);
|
||||
delete it->second;
|
||||
it = m_Prop3Ds.erase(it);
|
||||
@@ -67,92 +72,97 @@ void ObjectsContext::Synchronize() {
|
||||
// Add Prop3Ds for new objects
|
||||
for (auto obj : objects) {
|
||||
if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) {
|
||||
Prop3D* prop3d = this->CreateProp3D(obj);
|
||||
Prop3D *prop3d = this->CreateProp3D(obj);
|
||||
if (prop3d) {
|
||||
m_Prop3Ds[obj] = prop3d;
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
|
||||
m_Assembly->AddPart(p3d);
|
||||
if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
|
||||
m_Assembly->AddPart(p3d);
|
||||
this->Prop3DAdded(prop3d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectsContext::OnObjectAdded(uLib::Object* obj) {
|
||||
if (!obj) return;
|
||||
void ObjectsContext::OnObjectAdded(uLib::Object *obj) {
|
||||
if (!obj)
|
||||
return;
|
||||
if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) {
|
||||
Prop3D* prop3d = this->CreateProp3D(obj);
|
||||
Prop3D *prop3d = this->CreateProp3D(obj);
|
||||
if (prop3d) {
|
||||
m_Prop3Ds[obj] = prop3d;
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
|
||||
m_Assembly->AddPart(p3d);
|
||||
if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
|
||||
m_Assembly->AddPart(p3d);
|
||||
this->Prop3DAdded(prop3d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectsContext::OnObjectRemoved(uLib::Object* obj) {
|
||||
if (!obj) return;
|
||||
auto it = m_Prop3Ds.find(obj);
|
||||
if (it != m_Prop3Ds.end()) {
|
||||
// For now we just remove from assembly.
|
||||
// Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily.
|
||||
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||
m_Assembly->RemovePart(p3d);
|
||||
this->Prop3DRemoved(it->second);
|
||||
delete it->second;
|
||||
m_Prop3Ds.erase(it);
|
||||
}
|
||||
void ObjectsContext::OnObjectRemoved(uLib::Object *obj) {
|
||||
if (!obj)
|
||||
return;
|
||||
auto it = m_Prop3Ds.find(obj);
|
||||
if (it != m_Prop3Ds.end()) {
|
||||
// For now we just remove from assembly.
|
||||
// Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't
|
||||
// have it here easily.
|
||||
if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||
m_Assembly->RemovePart(p3d);
|
||||
this->Prop3DRemoved(it->second);
|
||||
delete it->second;
|
||||
m_Prop3Ds.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
Prop3D* ObjectsContext::GetProp3D(uLib::Object* obj) {
|
||||
Prop3D *ObjectsContext::GetProp3D(uLib::Object *obj) {
|
||||
auto it = m_Prop3Ds.find(obj);
|
||||
if (it != m_Prop3Ds.end()) return it->second;
|
||||
if (it != m_Prop3Ds.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ObjectsContext::Update() {
|
||||
for (auto const& [obj, prop3d] : m_Prop3Ds) {
|
||||
for (auto const &[obj, prop3d] : m_Prop3Ds) {
|
||||
prop3d->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectsContext::SyncFromVtk() {
|
||||
for (auto const& [obj, prop3d] : m_Prop3Ds) {
|
||||
for (auto const &[obj, prop3d] : m_Prop3Ds) {
|
||||
prop3d->SyncFromVtk();
|
||||
}
|
||||
}
|
||||
|
||||
Prop3D* ObjectsContext::CreateProp3D(uLib::Object* obj) {
|
||||
if (!obj) return nullptr;
|
||||
Prop3D *ObjectsContext::CreateProp3D(uLib::Object *obj) {
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (auto* vox = dynamic_cast<uLib::Abstract::VoxImage*>(obj)) {
|
||||
return new VoxImage(*vox);
|
||||
} else if (auto* box = dynamic_cast<uLib::ContainerBox*>(obj)) {
|
||||
if (auto *vox = dynamic_cast<uLib::Abstract::VoxImage *>(obj)) {
|
||||
return new VoxImage(vox);
|
||||
} else if (auto *box = dynamic_cast<uLib::ContainerBox *>(obj)) {
|
||||
return new ContainerBox(box);
|
||||
} else if (auto* chamber = dynamic_cast<uLib::DetectorChamber*>(obj)) {
|
||||
} else if (auto *chamber = dynamic_cast<uLib::DetectorChamber *>(obj)) {
|
||||
return new DetectorChamber(chamber);
|
||||
} else if (auto* cylinder = dynamic_cast<uLib::Cylinder*>(obj)) {
|
||||
} else if (auto *cylinder = dynamic_cast<uLib::Cylinder *>(obj)) {
|
||||
return new Cylinder(cylinder);
|
||||
} else if (auto* assembly = dynamic_cast<uLib::Assembly*>(obj)) {
|
||||
} else if (auto *assembly = dynamic_cast<uLib::Assembly *>(obj)) {
|
||||
return new Assembly(assembly);
|
||||
} else if (auto* box = dynamic_cast<uLib::Geant::BoxSolid*>(obj)) {
|
||||
} else if (auto *box = dynamic_cast<uLib::Geant::BoxSolid *>(obj)) {
|
||||
return new BoxSolid(box);
|
||||
}
|
||||
|
||||
|
||||
// Fallback if we don't know the exact class but it might be a context itself
|
||||
if (auto subCtx = dynamic_cast<uLib::ObjectsContext*>(obj)) {
|
||||
return new ObjectsContext(subCtx);
|
||||
if (auto subCtx = dynamic_cast<uLib::ObjectsContext *>(obj)) {
|
||||
return new ObjectsContext(subCtx);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ObjectsContext::Prop3DAdded(Prop3D* prop3d) {
|
||||
void ObjectsContext::Prop3DAdded(Prop3D *prop3d) {
|
||||
ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DAdded, prop3d);
|
||||
}
|
||||
|
||||
void ObjectsContext::Prop3DRemoved(Prop3D* prop3d) {
|
||||
void ObjectsContext::Prop3DRemoved(Prop3D *prop3d) {
|
||||
ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DRemoved, prop3d);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user