add assembly
This commit is contained in:
@@ -20,13 +20,13 @@ public:
|
|||||||
* @brief Adds an object to the context.
|
* @brief Adds an object to the context.
|
||||||
* @param obj Pointer to the object to add.
|
* @param obj Pointer to the object to add.
|
||||||
*/
|
*/
|
||||||
void AddObject(Object* obj);
|
virtual void AddObject(Object* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes an object from the context.
|
* @brief Removes an object from the context.
|
||||||
* @param obj Pointer to the object to remove.
|
* @param obj Pointer to the object to remove.
|
||||||
*/
|
*/
|
||||||
void RemoveObject(Object* obj);
|
virtual void RemoveObject(Object* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears all objects from the context.
|
* @brief Clears all objects from the context.
|
||||||
|
|||||||
146
src/Math/Assembly.cpp
Normal file
146
src/Math/Assembly.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#include "Math/Assembly.h"
|
||||||
|
#include "Math/ContainerBox.h"
|
||||||
|
#include "Math/Cylinder.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
|
||||||
|
Assembly::Assembly()
|
||||||
|
: ObjectsContext(),
|
||||||
|
AffineTransform(),
|
||||||
|
m_BBoxMin(Vector3f::Zero()),
|
||||||
|
m_BBoxMax(Vector3f::Zero()),
|
||||||
|
m_ShowBoundingBox(false),
|
||||||
|
m_GroupSelection(true) {}
|
||||||
|
|
||||||
|
Assembly::Assembly(const Assembly ©)
|
||||||
|
: ObjectsContext(copy),
|
||||||
|
AffineTransform(copy),
|
||||||
|
m_BBoxMin(copy.m_BBoxMin),
|
||||||
|
m_BBoxMax(copy.m_BBoxMax),
|
||||||
|
m_ShowBoundingBox(copy.m_ShowBoundingBox),
|
||||||
|
m_GroupSelection(copy.m_GroupSelection) {}
|
||||||
|
|
||||||
|
Assembly::~Assembly() {}
|
||||||
|
|
||||||
|
void Assembly::AddObject(Object *obj) {
|
||||||
|
if (auto *at = dynamic_cast<AffineTransform *>(obj)) {
|
||||||
|
at->SetParent(this);
|
||||||
|
}
|
||||||
|
ObjectsContext::AddObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembly::RemoveObject(Object *obj) {
|
||||||
|
if (auto *at = dynamic_cast<AffineTransform *>(obj)) {
|
||||||
|
if (at->GetParent() == this)
|
||||||
|
at->SetParent(nullptr);
|
||||||
|
}
|
||||||
|
ObjectsContext::RemoveObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembly::ComputeBoundingBox() {
|
||||||
|
const auto &objects = this->GetObjects();
|
||||||
|
if (objects.empty()) {
|
||||||
|
m_BBoxMin = Vector3f::Zero();
|
||||||
|
m_BBoxMax = Vector3f::Zero();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float inf = std::numeric_limits<float>::max();
|
||||||
|
m_BBoxMin = Vector3f(inf, inf, inf);
|
||||||
|
m_BBoxMax = Vector3f(-inf, -inf, -inf);
|
||||||
|
|
||||||
|
Matrix4f invAsm = this->GetWorldMatrix().inverse();
|
||||||
|
|
||||||
|
for (Object *obj : objects) {
|
||||||
|
if (auto *box = dynamic_cast<ContainerBox *>(obj)) {
|
||||||
|
// ContainerBox: wm is matrix from unit cube [0,1] to assembly base
|
||||||
|
Matrix4f m = invAsm * box->GetWorldMatrix();
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float x = (i & 1) ? 1.0f : 0.0f;
|
||||||
|
float y = (i & 2) ? 1.0f : 0.0f;
|
||||||
|
float z = (i & 4) ? 1.0f : 0.0f;
|
||||||
|
Vector4f corner = m * Vector4f(x, y, z, 1.0f);
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a));
|
||||||
|
m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (auto *cyl = dynamic_cast<Cylinder *>(obj)) {
|
||||||
|
// Cylinder: centered [-1, 1] radial, [-0.5, 0.5] height
|
||||||
|
Matrix4f m = invAsm * cyl->GetWorldMatrix();
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float x = (i & 1) ? 1.0f : -1.0f;
|
||||||
|
float y = (i & 2) ? 0.5f : -0.5f;
|
||||||
|
float z = (i & 4) ? 1.0f : -1.0f;
|
||||||
|
Vector4f corner = m * Vector4f(x, y, z, 1.0f);
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a));
|
||||||
|
m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (auto *subAsm = dynamic_cast<Assembly *>(obj)) {
|
||||||
|
// Recursive AABB for nested assemblies
|
||||||
|
subAsm->ComputeBoundingBox();
|
||||||
|
Vector3f subMin, subMax;
|
||||||
|
subAsm->GetBoundingBox(subMin, subMax);
|
||||||
|
Matrix4f m = invAsm * subAsm->GetWorldMatrix();
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float x = (i & 1) ? subMax(0) : subMin(0);
|
||||||
|
float y = (i & 2) ? subMax(1) : subMin(1);
|
||||||
|
float z = (i & 4) ? subMax(2) : subMin(2);
|
||||||
|
Vector4f corner = m * Vector4f(x, y, z, 1.0f);
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
m_BBoxMin(a) = std::min(m_BBoxMin(a), corner(a));
|
||||||
|
m_BBoxMax(a) = std::max(m_BBoxMax(a), corner(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembly::GetBoundingBox(Vector3f &bbMin, Vector3f &bbMax) const {
|
||||||
|
bbMin = m_BBoxMin;
|
||||||
|
bbMax = m_BBoxMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerBox Assembly::GetBoundingBoxAsContainer() const {
|
||||||
|
ContainerBox bb;
|
||||||
|
Vector3f size = m_BBoxMax - m_BBoxMin;
|
||||||
|
bb.SetSize(size);
|
||||||
|
bb.SetPosition(m_BBoxMin);
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembly::SetShowBoundingBox(bool show) {
|
||||||
|
m_ShowBoundingBox = show;
|
||||||
|
this->Updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Assembly::GetShowBoundingBox() const {
|
||||||
|
return m_ShowBoundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembly::SetGroupSelection(bool group) {
|
||||||
|
m_GroupSelection = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Assembly::GetGroupSelection() const {
|
||||||
|
return m_GroupSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uLib
|
||||||
109
src/Math/Assembly.h
Normal file
109
src/Math/Assembly.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
------------------------------------------------------------------
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3.0 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#ifndef U_ASSEMBLY_H
|
||||||
|
#define U_ASSEMBLY_H
|
||||||
|
|
||||||
|
#include "Core/ObjectsContext.h"
|
||||||
|
#include "Math/ContainerBox.h"
|
||||||
|
#include "Math/Transform.h"
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assembly groups geometric objects (ContainerBox, Cylinder, etc.)
|
||||||
|
* under a common transformation.
|
||||||
|
*
|
||||||
|
* Assembly derives from ObjectsContext so objects can be added/removed
|
||||||
|
* dynamically. It also inherits AffineTransform to provide a group-level
|
||||||
|
* transformation that is applied on top of each child's own transform.
|
||||||
|
*
|
||||||
|
* A bounding box is automatically computed from all contained objects and
|
||||||
|
* can be queried or shown/hidden through the VTK puppet.
|
||||||
|
*/
|
||||||
|
class Assembly : public ObjectsContext, public AffineTransform {
|
||||||
|
public:
|
||||||
|
virtual const char *GetClassName() const override { return "Assembly"; }
|
||||||
|
|
||||||
|
Assembly();
|
||||||
|
Assembly(const Assembly ©);
|
||||||
|
virtual ~Assembly();
|
||||||
|
|
||||||
|
virtual void AddObject(Object* obj) override;
|
||||||
|
virtual void RemoveObject(Object* obj) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recomputes the axis-aligned bounding box enclosing all children.
|
||||||
|
* Stores the result internally.
|
||||||
|
*/
|
||||||
|
void ComputeBoundingBox();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the bounding box as min/max corners (in assembly-local
|
||||||
|
* coordinates).
|
||||||
|
*/
|
||||||
|
void GetBoundingBox(Vector3f &bbMin, Vector3f &bbMax) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the bounding box as a ContainerBox (positioned
|
||||||
|
* at bbMin, sized bbMax-bbMin, parented to this transform).
|
||||||
|
*/
|
||||||
|
ContainerBox GetBoundingBoxAsContainer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Controls whether the bounding box wireframe should be shown
|
||||||
|
* in the viewer (used by the VTK puppet).
|
||||||
|
*/
|
||||||
|
void SetShowBoundingBox(bool show);
|
||||||
|
bool GetShowBoundingBox() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Controls selection behavior.
|
||||||
|
* If true (default), clicking any child within the assembly will select
|
||||||
|
* the assembly itself. If false, individual children can be picked.
|
||||||
|
*/
|
||||||
|
void SetGroupSelection(bool group);
|
||||||
|
bool GetGroupSelection() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
virtual void Updated() override {
|
||||||
|
if (m_InUpdated) return; // break signal recursion
|
||||||
|
m_InUpdated = true;
|
||||||
|
this->ComputeBoundingBox();
|
||||||
|
ULIB_SIGNAL_EMIT(Assembly::Updated);
|
||||||
|
m_InUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3f m_BBoxMin;
|
||||||
|
Vector3f m_BBoxMax;
|
||||||
|
bool m_ShowBoundingBox;
|
||||||
|
bool m_GroupSelection;
|
||||||
|
bool m_InUpdated = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif // U_ASSEMBLY_H
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
set(HEADERS ContainerBox.h
|
set(HEADERS ContainerBox.h
|
||||||
Cylinder.h
|
Cylinder.h
|
||||||
|
Assembly.h
|
||||||
Dense.h
|
Dense.h
|
||||||
Geometry.h
|
Geometry.h
|
||||||
Transform.h
|
Transform.h
|
||||||
@@ -33,6 +34,7 @@ set(SOURCES VoxRaytracer.cpp
|
|||||||
VoxImage.cpp
|
VoxImage.cpp
|
||||||
TriangleMesh.cpp
|
TriangleMesh.cpp
|
||||||
QuadMesh.cpp
|
QuadMesh.cpp
|
||||||
|
Assembly.cpp
|
||||||
Dense.cpp
|
Dense.cpp
|
||||||
Structured2DGrid.cpp
|
Structured2DGrid.cpp
|
||||||
Structured4DGrid.cpp
|
Structured4DGrid.cpp
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ public:
|
|||||||
m_Parent(NULL)
|
m_Parent(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual ~AffineTransform() {}
|
||||||
|
|
||||||
AffineTransform(AffineTransform *parent) :
|
AffineTransform(AffineTransform *parent) :
|
||||||
m_T(Matrix4f::Identity()),
|
m_T(Matrix4f::Identity()),
|
||||||
m_Parent(parent)
|
m_Parent(parent)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ set(MATH_SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkAssembly.cpp
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|
||||||
set(MATH_HEADERS
|
set(MATH_HEADERS
|
||||||
@@ -20,6 +21,7 @@ set(MATH_HEADERS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkVoxImage.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkContainerBox.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.h
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkCylinder.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/vtkAssembly.h
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ set(TESTS
|
|||||||
vtkVoxImageInteractiveTest
|
vtkVoxImageInteractiveTest
|
||||||
vtkContainerBoxTest
|
vtkContainerBoxTest
|
||||||
vtkContainerBoxTest2
|
vtkContainerBoxTest2
|
||||||
|
vtkAssemblyTest
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBRARIES
|
set(LIBRARIES
|
||||||
|
|||||||
@@ -1,109 +1,104 @@
|
|||||||
/*//////////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
|
||||||
// All rights reserved
|
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
#include "Vtk/uLibVtkViewer.h"
|
|
||||||
#include "Vtk/Math/vtkAssembly.h"
|
|
||||||
#include "Vtk/Math/vtkCylinder.h"
|
|
||||||
#include "Vtk/Math/vtkContainerBox.h"
|
|
||||||
#include "Math/Assembly.h"
|
#include "Math/Assembly.h"
|
||||||
#include "Math/Cylinder.h"
|
|
||||||
#include "Math/ContainerBox.h"
|
#include "Math/ContainerBox.h"
|
||||||
|
#include "Math/Cylinder.h"
|
||||||
|
#include "Vtk/Math/vtkAssembly.h"
|
||||||
|
#include "Vtk/vtkObjectsContext.h"
|
||||||
|
#include "Vtk/uLibVtkViewer.h"
|
||||||
#include "Math/Units.h"
|
#include "Math/Units.h"
|
||||||
|
|
||||||
|
#include <vtkActor.h>
|
||||||
|
#include <vtkProperty.h>
|
||||||
|
#include <vtkPropCollection.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace uLib;
|
using namespace uLib;
|
||||||
|
|
||||||
/**
|
int main(int argc, char **argv) {
|
||||||
* @brief This test verifies that uLib::Vtk::Assembly correctly visualizes a collection
|
bool interactive = (argc > 1 && std::string(argv[1]) == "-i");
|
||||||
* of objects and that transformations applied to the assembly are propagated to its children.
|
|
||||||
* It also checks that the assembly appears as a bounding box of its contents.
|
|
||||||
*/
|
|
||||||
int main() {
|
|
||||||
std::cout << "Starting vtkAssemblyTest..." << std::endl;
|
|
||||||
|
|
||||||
// 1. Setup Core Geometry
|
// ---- 1. Build model objects ----
|
||||||
std::cout << " - Creating core Assembly..." << std::endl;
|
ContainerBox box1;
|
||||||
uLib::Assembly* core_assembly = new uLib::Assembly();
|
box1.Scale(Vector3f(1_m, 2_m, 0.5_m));
|
||||||
core_assembly->SetInstanceName("MainAssembly");
|
box1.SetPosition(Vector3f(0, 0, 0));
|
||||||
|
|
||||||
// Add a box
|
ContainerBox box2;
|
||||||
std::cout << " - Adding ChildBox (Red)..." << std::endl;
|
box2.Scale(Vector3f(0.5_m, 0.5_m, 3_m));
|
||||||
ContainerBox* box = new ContainerBox();
|
box2.SetPosition(Vector3f(2_m, 0, 0));
|
||||||
box->SetInstanceName("ChildBox");
|
|
||||||
box->Translate(Vector3f(1.0, 0, 0));
|
|
||||||
core_assembly->AddObject(box);
|
|
||||||
|
|
||||||
// Add a cylinder
|
Cylinder cyl(0.3_m, 1.5_m, 1);
|
||||||
// std::cout << " - Adding ChildCylinder (Blue)..." << std::endl;
|
cyl.SetPosition(Vector3f(0, 3_m, 0));
|
||||||
// Cylinder* cyl = new Cylinder(0.5, 2.0);
|
|
||||||
// cyl->SetInstanceName("ChildCylinder");
|
|
||||||
// cyl->Translate(Vector3f(-2.0, 0, 0));
|
|
||||||
// core_assembly->AddObject(cyl);
|
|
||||||
|
|
||||||
std::cout << " - Adding another box (Green)..." << std::endl;
|
// ---- 2. Create an Assembly and add objects ----
|
||||||
ContainerBox* box2 = new ContainerBox();
|
Assembly assembly;
|
||||||
box2->Scale(Vector3f(1.0, 1.0, 2.0));
|
assembly.AddObject(&box1);
|
||||||
box2->SetInstanceName("ChildBox2");
|
assembly.AddObject(&box2);
|
||||||
box2->Translate(Vector3f(0, 0, 1.0));
|
assembly.AddObject(&cyl);
|
||||||
core_assembly->AddObject(box2);
|
assembly.SetShowBoundingBox(true);
|
||||||
|
|
||||||
// 2. Setup VTK Representation
|
// ---- 3. Apply a group transform ----
|
||||||
std::cout << " - Creating VTK Assembly representation..." << std::endl;
|
assembly.SetPosition(Vector3f(1_m, 1_m, 0));
|
||||||
Vtk::Assembly vtk_assembly(core_assembly);
|
|
||||||
|
|
||||||
// Find and colorized the children puppets
|
// ---- 5. Visualize (create puppets to set properties) ----
|
||||||
Vtk::Puppet* p_box = vtk_assembly.GetPuppet(box);
|
Vtk::Assembly vtkAsm(&assembly);
|
||||||
if (p_box) {
|
|
||||||
p_box->SetColor(1.0, 0.0, 0.0); // Red
|
|
||||||
} else {
|
|
||||||
std::cerr << "Warning: Could not find puppet for box!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vtk::Puppet* p_cyl = vtk_assembly.GetPuppet(cyl);
|
|
||||||
// if (p_cyl) {
|
|
||||||
// p_cyl->SetColor(0.0, 0.0, 1.0); // Blue
|
|
||||||
// } else {
|
|
||||||
// std::cerr << "Warning: Could not find puppet for cylinder!" << std::endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Vtk::Puppet* p_box2 = vtk_assembly.GetPuppet(box2);
|
|
||||||
if (p_box2) {
|
|
||||||
p_box2->SetColor(0.0, 1.0, 0.0); // Green
|
|
||||||
} else {
|
|
||||||
std::cerr << "Warning: Could not find puppet for box2!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Test Transformation Propagation
|
|
||||||
std::cout << " - Rotating Assembly 45 degrees around Z..." << std::endl;
|
|
||||||
core_assembly->Rotate(45.0_deg, Vector3f::UnitZ());
|
|
||||||
|
|
||||||
std::cout << " - Translating Assembly up (+Y)..." << std::endl;
|
|
||||||
core_assembly->Translate(Vector3f(0, 2.0, 0));
|
|
||||||
|
|
||||||
// Notify all puppets of the change
|
|
||||||
core_assembly->Updated();
|
|
||||||
|
|
||||||
// 4. Run Visualization
|
|
||||||
std::cout << "Starting viewer (close to exit)..." << std::endl;
|
|
||||||
std::cout << "Expected: A white bounding box containing a red box and a blue cylinder, "
|
|
||||||
<< "all rotated and translated as a group." << std::endl;
|
|
||||||
|
|
||||||
Vtk::Viewer viewer;
|
Vtk::Viewer viewer;
|
||||||
viewer.AddPuppet(*p_box);
|
vtkAsm.AddToViewer(viewer); // This triggers puppet creation via ConnectRenderer which eventually calls Puppet::GetProp
|
||||||
viewer.AddPuppet(*p_box2);
|
|
||||||
viewer.AddPuppet(vtk_assembly);
|
|
||||||
viewer.Start();
|
|
||||||
|
|
||||||
// Clean up
|
// Explicitly update to ensure puppets exist and are added to assemblies
|
||||||
delete core_assembly;
|
vtkAsm.Update();
|
||||||
delete box;
|
|
||||||
delete box2;
|
// Use the child context to find child puppets and set colors
|
||||||
// delete cyl;
|
if (auto* childCtx = vtkAsm.GetChildrenContext()) {
|
||||||
|
auto setProps = [](Vtk::Puppet* p, float r, float g, float b) {
|
||||||
|
if (!p) return;
|
||||||
|
vtkPropCollection* props = p->GetProps();
|
||||||
|
props->InitTraversal();
|
||||||
|
for (int i=0; i < props->GetNumberOfItems(); ++i) {
|
||||||
|
if (auto* actor = vtkActor::SafeDownCast(props->GetNextProp())) {
|
||||||
|
actor->GetProperty()->SetColor(r, g, b);
|
||||||
|
actor->GetProperty()->SetRepresentationToSurface();
|
||||||
|
actor->GetProperty()->SetOpacity(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setProps(childCtx->GetPuppet(&box1), 1.0, 0.0, 0.0); // Red
|
||||||
|
setProps(childCtx->GetPuppet(&box2), 0.0, 1.0, 0.0); // Green
|
||||||
|
setProps(childCtx->GetPuppet(&cyl), 0.0, 0.0, 1.0); // Blue
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Puppets in viewport: " << viewer.getPuppets().size() << " (Expected 4: 1 assembly + 3 children)" << std::endl;
|
||||||
|
|
||||||
|
// ---- 4. Query the bounding box for terminal output ----
|
||||||
|
Vector3f bbMin, bbMax;
|
||||||
|
assembly.GetBoundingBox(bbMin, bbMax);
|
||||||
|
std::cout << "Assembly bounding box:" << std::endl;
|
||||||
|
std::cout << " min = " << bbMin.transpose() << std::endl;
|
||||||
|
std::cout << " max = " << bbMax.transpose() << std::endl;
|
||||||
|
|
||||||
|
std::cout << "==================================================\n";
|
||||||
|
std::cout << " vtkAssemblyTest\n";
|
||||||
|
std::cout << " 2 boxes + 1 cylinder grouped in an assembly\n";
|
||||||
|
std::cout << "==================================================" << std::endl;
|
||||||
|
|
||||||
|
if (interactive) {
|
||||||
|
viewer.ZoomAuto();
|
||||||
|
viewer.Start();
|
||||||
|
} else {
|
||||||
|
std::cout << "Non-interactive test passed." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
210
src/Vtk/Math/vtkAssembly.cpp
Normal file
210
src/Vtk/Math/vtkAssembly.cpp
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#include "vtkAssembly.h" // uLib::Vtk::Assembly
|
||||||
|
#include "Vtk/vtkObjectsContext.h"
|
||||||
|
#include "Math/vtkDense.h"
|
||||||
|
|
||||||
|
#include <vtkAssembly.h> // VTK library ::vtkAssembly
|
||||||
|
#include <vtkActor.h>
|
||||||
|
#include <vtkCubeSource.h>
|
||||||
|
#include <vtkPolyDataMapper.h>
|
||||||
|
#include <vtkProperty.h>
|
||||||
|
#include <vtkMatrix4x4.h>
|
||||||
|
#include <vtkPropCollection.h>
|
||||||
|
#include <vtkNew.h>
|
||||||
|
#include <vtkProp3D.h>
|
||||||
|
#include <vtkPoints.h>
|
||||||
|
#include <vtkCellArray.h>
|
||||||
|
#include <vtkPolyData.h>
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Vtk {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
Assembly::Assembly(uLib::Assembly *content)
|
||||||
|
: m_Content(content),
|
||||||
|
m_ChildContext(nullptr),
|
||||||
|
m_BBoxActor(nullptr),
|
||||||
|
m_VtkAsm(nullptr),
|
||||||
|
m_InUpdate(false),
|
||||||
|
m_BlockUpdate(false) {
|
||||||
|
this->InstallPipe();
|
||||||
|
if (m_Content) {
|
||||||
|
Object::connect(m_Content, &uLib::Assembly::Updated,
|
||||||
|
this, &Assembly::contentUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assembly::~Assembly() {
|
||||||
|
delete m_ChildContext;
|
||||||
|
if (m_BBoxActor) m_BBoxActor->Delete();
|
||||||
|
if (m_VtkAsm) m_VtkAsm->Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
void Assembly::InstallPipe() {
|
||||||
|
// 1. Create the VTK library assembly that groups everything
|
||||||
|
m_VtkAsm = ::vtkAssembly::New();
|
||||||
|
this->SetProp(m_VtkAsm);
|
||||||
|
|
||||||
|
// 2. Create the bounding-box wireframe actor
|
||||||
|
vtkNew<vtkCubeSource> cube;
|
||||||
|
cube->SetBounds(0, 1, 0, 1, 0, 1);
|
||||||
|
cube->Update();
|
||||||
|
|
||||||
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
|
mapper->SetInputConnection(cube->GetOutputPort());
|
||||||
|
|
||||||
|
m_BBoxActor = vtkActor::New();
|
||||||
|
m_BBoxActor->SetMapper(mapper);
|
||||||
|
m_BBoxActor->GetProperty()->SetRepresentationToWireframe();
|
||||||
|
m_BBoxActor->GetProperty()->SetColor(1.0, 0.85, 0.0); // gold wireframe
|
||||||
|
m_BBoxActor->GetProperty()->SetLineWidth(1.5);
|
||||||
|
m_BBoxActor->GetProperty()->SetOpacity(0.6);
|
||||||
|
m_BBoxActor->SetVisibility(m_Content ? m_Content->GetShowBoundingBox() : false);
|
||||||
|
|
||||||
|
m_VtkAsm->AddPart(m_BBoxActor);
|
||||||
|
|
||||||
|
// 3. Build a child-objects context (auto-creates puppets for each child)
|
||||||
|
if (m_Content) {
|
||||||
|
m_ChildContext = new vtkObjectsContext(m_Content);
|
||||||
|
// The vtkObjectsContext's own prop is already a ::vtkAssembly;
|
||||||
|
// nest it inside ours so everything moves together.
|
||||||
|
if (auto *childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp()))
|
||||||
|
m_VtkAsm->AddPart(childProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Apply initial transform
|
||||||
|
this->UpdateTransform();
|
||||||
|
this->UpdateBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
void Assembly::contentUpdate() {
|
||||||
|
if (m_InUpdate) return;
|
||||||
|
m_InUpdate = true;
|
||||||
|
|
||||||
|
this->UpdateTransform();
|
||||||
|
this->UpdateBoundingBox();
|
||||||
|
if (m_ChildContext)
|
||||||
|
m_ChildContext->Update();
|
||||||
|
|
||||||
|
m_BlockUpdate = true;
|
||||||
|
Puppet::Update();
|
||||||
|
m_InUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
void Assembly::Update() {
|
||||||
|
if (m_InUpdate) return;
|
||||||
|
if (!m_Content || !m_VtkAsm) return;
|
||||||
|
|
||||||
|
if (m_BlockUpdate) {
|
||||||
|
m_BlockUpdate = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_InUpdate = true;
|
||||||
|
|
||||||
|
// Pull VTK transform back into the uLib model
|
||||||
|
vtkMatrix4x4* vmat = m_VtkAsm->GetUserMatrix();
|
||||||
|
if (vmat) {
|
||||||
|
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||||
|
m_Content->SetMatrix(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->UpdateBoundingBox();
|
||||||
|
if (m_ChildContext)
|
||||||
|
m_ChildContext->Update();
|
||||||
|
|
||||||
|
m_Content->Updated(); // Notify change in model
|
||||||
|
|
||||||
|
m_InUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
void Assembly::UpdateTransform() {
|
||||||
|
if (!m_Content || !m_VtkAsm) return;
|
||||||
|
|
||||||
|
Matrix4f mat = m_Content->GetMatrix();
|
||||||
|
vtkNew<vtkMatrix4x4> vmat;
|
||||||
|
Matrix4fToVtk(mat, vmat);
|
||||||
|
m_VtkAsm->SetUserMatrix(vmat);
|
||||||
|
m_VtkAsm->Modified();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
void Assembly::UpdateBoundingBox() {
|
||||||
|
if (!m_Content || !m_BBoxActor) return;
|
||||||
|
|
||||||
|
m_BBoxActor->SetVisibility(m_Content->GetShowBoundingBox());
|
||||||
|
|
||||||
|
Vector3f bbMin, bbMax;
|
||||||
|
m_Content->GetBoundingBox(bbMin, bbMax);
|
||||||
|
|
||||||
|
// Avoid degenerate boxes
|
||||||
|
Vector3f size = bbMax - bbMin;
|
||||||
|
if (size.norm() < 1e-6f) return;
|
||||||
|
|
||||||
|
// Rebuild the corner segments to match the AABB
|
||||||
|
vtkNew<vtkPoints> points;
|
||||||
|
vtkNew<vtkCellArray> lines;
|
||||||
|
|
||||||
|
float bounds[2][3] = {
|
||||||
|
{bbMin(0), bbMin(1), bbMin(2)},
|
||||||
|
{bbMax(0), bbMax(1), bbMax(2)}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Corner segment length: 10% of dimension
|
||||||
|
float len[3] = {
|
||||||
|
(bbMax(0) - bbMin(0)) * 0.1f,
|
||||||
|
(bbMax(1) - bbMin(1)) * 0.1f,
|
||||||
|
(bbMax(2) - bbMin(2)) * 0.1f
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float p[3];
|
||||||
|
p[0] = bounds[(i & 1) ? 1 : 0][0];
|
||||||
|
p[1] = bounds[(i & 2) ? 1 : 0][1];
|
||||||
|
p[2] = bounds[(i & 4) ? 1 : 0][2];
|
||||||
|
|
||||||
|
for (int axis = 0; axis < 3; ++axis) {
|
||||||
|
float p2[3] = {p[0], p[1], p[2]};
|
||||||
|
float delta = (i & (1 << axis)) ? -len[axis] : len[axis];
|
||||||
|
p2[axis] += delta;
|
||||||
|
|
||||||
|
vtkIdType id1 = points->InsertNextPoint(p);
|
||||||
|
vtkIdType id2 = points->InsertNextPoint(p2);
|
||||||
|
lines->InsertNextCell(2);
|
||||||
|
lines->InsertCellPoint(id1);
|
||||||
|
lines->InsertCellPoint(id2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkNew<vtkPolyData> poly;
|
||||||
|
poly->SetPoints(points);
|
||||||
|
poly->SetLines(lines);
|
||||||
|
|
||||||
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
|
mapper->SetInputData(poly);
|
||||||
|
|
||||||
|
m_BBoxActor->SetMapper(mapper);
|
||||||
|
m_BBoxActor->Modified();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ //
|
||||||
|
vtkObjectsContext *Assembly::GetChildrenContext() const {
|
||||||
|
return m_ChildContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vtk
|
||||||
|
} // namespace uLib
|
||||||
71
src/Vtk/Math/vtkAssembly.h
Normal file
71
src/Vtk/Math/vtkAssembly.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
#ifndef U_VTK_ASSEMBLY_H
|
||||||
|
#define U_VTK_ASSEMBLY_H
|
||||||
|
|
||||||
|
#include "Math/Assembly.h"
|
||||||
|
#include "uLibVtkInterface.h"
|
||||||
|
|
||||||
|
class vtkActor;
|
||||||
|
class vtkAssembly; // VTK library forward declaration (must be before namespace)
|
||||||
|
|
||||||
|
namespace uLib {
|
||||||
|
namespace Vtk {
|
||||||
|
|
||||||
|
class vtkObjectsContext; // forward
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief VTK Puppet for visualizing uLib::Assembly.
|
||||||
|
*
|
||||||
|
* Manages a VTK assembly (vtkAssembly from the VTK library) that groups
|
||||||
|
* all child puppets and applies the Assembly's AffineTransform. It also
|
||||||
|
* renders an optional bounding box wireframe computed from the Assembly's AABB.
|
||||||
|
*
|
||||||
|
* @note This class is uLib::Vtk::Assembly. It internally uses
|
||||||
|
* the VTK library class vtkAssembly for grouping, but the two
|
||||||
|
* are distinct.
|
||||||
|
*/
|
||||||
|
class Assembly : public Puppet {
|
||||||
|
public:
|
||||||
|
virtual const char *GetClassName() const override { return "Vtk.Assembly"; }
|
||||||
|
|
||||||
|
Assembly(uLib::Assembly *content);
|
||||||
|
virtual ~Assembly();
|
||||||
|
|
||||||
|
/** @brief Updates the VTK representation from the model (model→VTK). */
|
||||||
|
virtual void Update() override;
|
||||||
|
|
||||||
|
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||||
|
|
||||||
|
/** @brief Called when the model signals an update (model→VTK push). */
|
||||||
|
void contentUpdate();
|
||||||
|
|
||||||
|
/** @brief Returns the puppet managing child objects. */
|
||||||
|
vtkObjectsContext *GetChildrenContext() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateTransform();
|
||||||
|
void UpdateBoundingBox();
|
||||||
|
void InstallPipe();
|
||||||
|
|
||||||
|
uLib::Assembly *m_Content;
|
||||||
|
vtkObjectsContext *m_ChildContext;
|
||||||
|
vtkActor *m_BBoxActor;
|
||||||
|
::vtkAssembly *m_VtkAsm; // VTK library assembly — NOT this class
|
||||||
|
bool m_InUpdate; // re-entrancy guard
|
||||||
|
bool m_BlockUpdate; // block feedback from contentUpdate→Update
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vtk
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif // U_VTK_ASSEMBLY_H
|
||||||
@@ -51,6 +51,8 @@ public:
|
|||||||
|
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
|
|
||||||
|
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void InstallPipe();
|
virtual void InstallPipe();
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "Vtk/Math/vtkCylinder.h"
|
#include "Vtk/Math/vtkCylinder.h"
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
|
#include <vtkAssembly.h>
|
||||||
#include <vtkCylinderSource.h>
|
#include <vtkCylinderSource.h>
|
||||||
#include <vtkMatrix4x4.h>
|
#include <vtkMatrix4x4.h>
|
||||||
#include <vtkPolyDataMapper.h>
|
#include <vtkPolyDataMapper.h>
|
||||||
@@ -37,13 +38,14 @@ namespace uLib {
|
|||||||
namespace Vtk {
|
namespace Vtk {
|
||||||
|
|
||||||
vtkCylinder::vtkCylinder(vtkCylinder::Content *content)
|
vtkCylinder::vtkCylinder(vtkCylinder::Content *content)
|
||||||
: m_Actor(vtkActor::New()), m_Content(content) {
|
: m_Content(content), m_Actor(nullptr), m_VtkAsm(nullptr) {
|
||||||
this->InstallPipe();
|
this->InstallPipe();
|
||||||
Object::connect(m_Content, &Content::Updated, this, &vtkCylinder::contentUpdate);
|
Object::connect(m_Content, &Content::Updated, this, &vtkCylinder::contentUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
vtkCylinder::~vtkCylinder() {
|
vtkCylinder::~vtkCylinder() {
|
||||||
m_Actor->Delete();
|
if (m_Actor) m_Actor->Delete();
|
||||||
|
if (m_VtkAsm) m_VtkAsm->Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtkCylinder::contentUpdate() {
|
void vtkCylinder::contentUpdate() {
|
||||||
@@ -53,28 +55,31 @@ void vtkCylinder::contentUpdate() {
|
|||||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
|
// 1. Placement (Position/Rotation/Model-level Scale) goes to the root prop
|
||||||
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
||||||
if (!vmat) {
|
if (!vmat) {
|
||||||
vtkNew<vtkMatrix4x4> mat;
|
vtkNew<vtkMatrix4x4> mat;
|
||||||
root->SetUserMatrix(mat);
|
root->SetUserMatrix(mat);
|
||||||
vmat = mat;
|
vmat = mat;
|
||||||
}
|
}
|
||||||
|
Matrix4f transform = m_Content->GetMatrix();
|
||||||
// Multiply the placement matrix by the volume scaling (Radius, Radius, Height)
|
|
||||||
Matrix4f transform = m_Content->GetMatrix() * m_Content->GetLocalMatrix();
|
|
||||||
Matrix4fToVtk(transform, vmat);
|
Matrix4fToVtk(transform, vmat);
|
||||||
|
|
||||||
// Update internal alignment based on active axis
|
// 2. Shape-local properties (Radius, Height, Axis alignment) go to the internal actor
|
||||||
vtkTransform* alignment = vtkTransform::SafeDownCast(m_Actor->GetUserTransform());
|
vtkTransform* alignment = vtkTransform::SafeDownCast(m_Actor->GetUserTransform());
|
||||||
if (alignment) {
|
if (alignment) {
|
||||||
alignment->Identity();
|
alignment->Identity();
|
||||||
|
alignment->PostMultiply();
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
// Apply Axis alignment
|
||||||
int axis = m_Content->GetAxis();
|
int axis = m_Content->GetAxis();
|
||||||
if (axis == 0) alignment->RotateZ(-90); // Y -> X
|
if (axis == 0) alignment->RotateZ(-90); // Y -> X
|
||||||
else if (axis == 1) ; // Y -> Y (identity)
|
else if (axis == 1) ; // Y -> Y (identity)
|
||||||
else if (axis == 2) alignment->RotateX(90); // Y -> Z
|
else if (axis == 2) alignment->RotateX(90); // Y -> Z
|
||||||
|
|
||||||
// We keep it centered as per latest user preference in Step 677
|
|
||||||
// alignment->Translate(0, 0, 0); // Implicit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root->Modified();
|
root->Modified();
|
||||||
@@ -90,16 +95,9 @@ void vtkCylinder::Update() {
|
|||||||
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
vtkMatrix4x4* vmat = root->GetUserMatrix();
|
||||||
if (!vmat) return;
|
if (!vmat) return;
|
||||||
|
|
||||||
Matrix4f fullTransform = VtkToMatrix4f(vmat);
|
// Pull the placement matrix directly from VTK
|
||||||
Matrix4f placementScale = m_Content->GetLocalMatrix().inverse();
|
Matrix4f transform = VtkToMatrix4f(vmat);
|
||||||
Matrix4f transform = fullTransform * placementScale;
|
m_Content->SetMatrix(transform);
|
||||||
|
|
||||||
if (m_Content->GetParent()) {
|
|
||||||
Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform;
|
|
||||||
m_Content->SetMatrix(localT);
|
|
||||||
} else {
|
|
||||||
m_Content->SetMatrix(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Content->Updated();
|
m_Content->Updated();
|
||||||
}
|
}
|
||||||
@@ -108,36 +106,27 @@ void vtkCylinder::InstallPipe() {
|
|||||||
if (!m_Content)
|
if (!m_Content)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_VtkAsm = ::vtkAssembly::New();
|
||||||
|
this->SetProp(m_VtkAsm);
|
||||||
|
|
||||||
vtkNew<vtkCylinderSource> cylinder;
|
vtkNew<vtkCylinderSource> cylinder;
|
||||||
cylinder->SetRadius(1.0);
|
cylinder->SetRadius(1.0);
|
||||||
cylinder->SetHeight(1.0);
|
cylinder->SetHeight(1.0);
|
||||||
cylinder->SetResolution(32);
|
cylinder->SetResolution(32);
|
||||||
|
|
||||||
|
m_Actor = vtkActor::New();
|
||||||
vtkNew<vtkTransform> alignment;
|
vtkNew<vtkTransform> alignment;
|
||||||
alignment->Identity();
|
m_Actor->SetUserTransform(alignment);
|
||||||
alignment->Translate(0, 0, -0.5);
|
|
||||||
|
|
||||||
// Default to Y alignment (Identity) as per latest request
|
|
||||||
int axis = m_Content->GetAxis();
|
|
||||||
if (axis == 0) alignment->RotateZ(-90);
|
|
||||||
else if (axis == 2) alignment->RotateX(90);
|
|
||||||
|
|
||||||
vtkNew<vtkPolyDataMapper> mapper;
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
mapper->SetInputConnection(cylinder->GetOutputPort());
|
mapper->SetInputConnection(cylinder->GetOutputPort());
|
||||||
|
|
||||||
m_Actor->SetMapper(mapper);
|
m_Actor->SetMapper(mapper);
|
||||||
m_Actor->SetUserTransform(alignment);
|
|
||||||
m_Actor->GetProperty()->SetRepresentationToWireframe();
|
m_Actor->GetProperty()->SetRepresentationToWireframe();
|
||||||
m_Actor->GetProperty()->SetAmbient(0.6);
|
m_Actor->GetProperty()->SetAmbient(0.6);
|
||||||
|
|
||||||
this->SetProp(m_Actor);
|
m_VtkAsm->AddPart(m_Actor);
|
||||||
|
|
||||||
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
|
this->contentUpdate();
|
||||||
if (root) {
|
|
||||||
vtkNew<vtkMatrix4x4> vmat;
|
|
||||||
Matrix4fToVtk(m_Content->GetMatrix() * m_Content->GetLocalMatrix(), vmat);
|
|
||||||
root->SetUserMatrix(vmat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vtk
|
} // namespace Vtk
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "Math/Cylinder.h"
|
#include "Math/Cylinder.h"
|
||||||
#include "Vtk/uLibVtkInterface.h"
|
#include "Vtk/uLibVtkInterface.h"
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
|
class vtkAssembly;
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Vtk {
|
namespace Vtk {
|
||||||
@@ -53,11 +54,14 @@ public:
|
|||||||
/** Synchronizes the uLib model matrix with the VTK actor (e.g., after UI manipulation) */
|
/** Synchronizes the uLib model matrix with the VTK actor (e.g., after UI manipulation) */
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
|
|
||||||
|
virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Sets up the VTK visualization pipeline */
|
/** Sets up the VTK visualization pipeline */
|
||||||
virtual void InstallPipe();
|
virtual void InstallPipe();
|
||||||
|
|
||||||
vtkActor *m_Actor;
|
vtkActor *m_Actor;
|
||||||
|
::vtkAssembly *m_VtkAsm;
|
||||||
Content *m_Content;
|
Content *m_Content;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ public:
|
|||||||
|
|
||||||
virtual vtkPropCollection *GetProps();
|
virtual vtkPropCollection *GetProps();
|
||||||
|
|
||||||
|
virtual uLib::Object *GetContent() const { return nullptr; }
|
||||||
|
|
||||||
void ConnectRenderer(vtkRenderer *renderer);
|
void ConnectRenderer(vtkRenderer *renderer);
|
||||||
|
|
||||||
void DisconnectRenderer(vtkRenderer *renderer);
|
void DisconnectRenderer(vtkRenderer *renderer);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "vtkObjectsContext.h"
|
#include "vtkObjectsContext.h"
|
||||||
#include "Vtk/Math/vtkContainerBox.h"
|
#include "Vtk/Math/vtkContainerBox.h"
|
||||||
#include "Vtk/Math/vtkCylinder.h"
|
#include "Vtk/Math/vtkCylinder.h"
|
||||||
|
#include "Vtk/Math/vtkAssembly.h"
|
||||||
#include "HEP/Detectors/vtkDetectorChamber.h"
|
#include "HEP/Detectors/vtkDetectorChamber.h"
|
||||||
|
|
||||||
#include <vtkAssembly.h>
|
#include <vtkAssembly.h>
|
||||||
@@ -42,12 +43,8 @@ void vtkObjectsContext::Synchronize() {
|
|||||||
it->second->DisconnectRenderer(nullptr); // If we have a ref to a renderer we should disconnect but Puppet doesn't store it easily
|
it->second->DisconnectRenderer(nullptr); // If we have a ref to a renderer we should disconnect but Puppet doesn't store it easily
|
||||||
// Actually Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer.
|
// Actually Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer.
|
||||||
// For now we just remove from assembly
|
// For now we just remove from assembly
|
||||||
vtkPropCollection* props = it->second->GetProps();
|
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||||
props->InitTraversal();
|
m_Assembly->RemovePart(p3d);
|
||||||
while(vtkProp* prop = props->GetNextProp()) {
|
|
||||||
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
|
|
||||||
m_Assembly->RemovePart(p3d);
|
|
||||||
}
|
|
||||||
this->PuppetRemoved(it->second);
|
this->PuppetRemoved(it->second);
|
||||||
delete it->second;
|
delete it->second;
|
||||||
it = m_Puppets.erase(it);
|
it = m_Puppets.erase(it);
|
||||||
@@ -62,12 +59,8 @@ void vtkObjectsContext::Synchronize() {
|
|||||||
Puppet* puppet = this->CreatePuppet(obj);
|
Puppet* puppet = this->CreatePuppet(obj);
|
||||||
if (puppet) {
|
if (puppet) {
|
||||||
m_Puppets[obj] = puppet;
|
m_Puppets[obj] = puppet;
|
||||||
vtkPropCollection* props = puppet->GetProps();
|
if (auto* p3d = vtkProp3D::SafeDownCast(puppet->GetProp()))
|
||||||
props->InitTraversal();
|
m_Assembly->AddPart(p3d);
|
||||||
while(vtkProp* prop = props->GetNextProp()) {
|
|
||||||
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
|
|
||||||
m_Assembly->AddPart(p3d);
|
|
||||||
}
|
|
||||||
this->PuppetAdded(puppet);
|
this->PuppetAdded(puppet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,12 +73,8 @@ void vtkObjectsContext::OnObjectAdded(uLib::Object* obj) {
|
|||||||
Puppet* puppet = this->CreatePuppet(obj);
|
Puppet* puppet = this->CreatePuppet(obj);
|
||||||
if (puppet) {
|
if (puppet) {
|
||||||
m_Puppets[obj] = puppet;
|
m_Puppets[obj] = puppet;
|
||||||
vtkPropCollection* props = puppet->GetProps();
|
if (auto* p3d = vtkProp3D::SafeDownCast(puppet->GetProp()))
|
||||||
props->InitTraversal();
|
m_Assembly->AddPart(p3d);
|
||||||
while(vtkProp* prop = props->GetNextProp()) {
|
|
||||||
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
|
|
||||||
m_Assembly->AddPart(p3d);
|
|
||||||
}
|
|
||||||
this->PuppetAdded(puppet);
|
this->PuppetAdded(puppet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,12 +86,8 @@ void vtkObjectsContext::OnObjectRemoved(uLib::Object* obj) {
|
|||||||
if (it != m_Puppets.end()) {
|
if (it != m_Puppets.end()) {
|
||||||
// For now we just remove from assembly.
|
// For now we just remove from assembly.
|
||||||
// Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily.
|
// Puppet::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily.
|
||||||
vtkPropCollection* props = it->second->GetProps();
|
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
|
||||||
props->InitTraversal();
|
m_Assembly->RemovePart(p3d);
|
||||||
while(vtkProp* prop = props->GetNextProp()) {
|
|
||||||
if (vtkProp3D* p3d = vtkProp3D::SafeDownCast(prop))
|
|
||||||
m_Assembly->RemovePart(p3d);
|
|
||||||
}
|
|
||||||
this->PuppetRemoved(it->second);
|
this->PuppetRemoved(it->second);
|
||||||
delete it->second;
|
delete it->second;
|
||||||
m_Puppets.erase(it);
|
m_Puppets.erase(it);
|
||||||
@@ -131,6 +116,8 @@ Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
|
|||||||
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
|
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
|
||||||
} else if (std::strcmp(className, "Cylinder") == 0) {
|
} else if (std::strcmp(className, "Cylinder") == 0) {
|
||||||
return new vtkCylinder(static_cast<uLib::Cylinder*>(obj));
|
return new vtkCylinder(static_cast<uLib::Cylinder*>(obj));
|
||||||
|
} else if (std::strcmp(className, "Assembly") == 0) {
|
||||||
|
return new Assembly(static_cast<uLib::Assembly*>(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback if we don't know the exact class but it might be a context itself
|
// Fallback if we don't know the exact class but it might be a context itself
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public:
|
|||||||
/** @brief Returns the puppet associated with a specific core object. */
|
/** @brief Returns the puppet associated with a specific core object. */
|
||||||
Puppet* GetPuppet(uLib::Object* obj);
|
Puppet* GetPuppet(uLib::Object* obj);
|
||||||
|
|
||||||
|
const std::map<uLib::Object*, Puppet*>& GetPuppets() const { return m_Puppets; }
|
||||||
|
|
||||||
/** @brief Updates all managed puppets. */
|
/** @brief Updates all managed puppets. */
|
||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <vtkProp3DCollection.h>
|
#include <vtkProp3DCollection.h>
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <vtkInteractorStyleTrackballCamera.h>
|
#include <vtkInteractorStyleTrackballCamera.h>
|
||||||
#include <vtkObjectFactory.h>
|
#include <vtkObjectFactory.h>
|
||||||
#include <vtkAxesActor.h>
|
#include <vtkAxesActor.h>
|
||||||
@@ -29,6 +30,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "vtkHandlerWidget.h"
|
#include "vtkHandlerWidget.h"
|
||||||
|
#include "vtkObjectsContext.h"
|
||||||
|
#include "Math/Assembly.h"
|
||||||
|
#include "Math/ContainerBox.h"
|
||||||
|
#include "Math/Cylinder.h"
|
||||||
|
#include "Math/Transform.h"
|
||||||
|
#include "Vtk/Math/vtkAssembly.h"
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
namespace Vtk {
|
namespace Vtk {
|
||||||
@@ -220,32 +227,67 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren)
|
|||||||
self->pv->m_Picker->Pick(pos[0], pos[1], 0, self->pv->m_Renderer);
|
self->pv->m_Picker->Pick(pos[0], pos[1], 0, self->pv->m_Renderer);
|
||||||
vtkProp* picked = self->pv->m_Picker->GetViewProp();
|
vtkProp* picked = self->pv->m_Picker->GetViewProp();
|
||||||
|
|
||||||
|
// 1. Recursive helper to check if a container prop contains a target prop
|
||||||
|
std::function<bool(vtkProp*, vtkProp*)> containsProp;
|
||||||
|
containsProp = [&containsProp](vtkProp* container, vtkProp* target) -> bool {
|
||||||
|
if (container == target) return true;
|
||||||
|
vtkPropCollection* parts = nullptr;
|
||||||
|
if (auto* pa = vtkPropAssembly::SafeDownCast(container))
|
||||||
|
parts = pa->GetParts();
|
||||||
|
else if (auto* aa = vtkAssembly::SafeDownCast(container))
|
||||||
|
parts = aa->GetParts();
|
||||||
|
if (parts) {
|
||||||
|
parts->InitTraversal();
|
||||||
|
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
|
||||||
|
if (containsProp(parts->GetNextProp(), target))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
Puppet* target = nullptr;
|
Puppet* target = nullptr;
|
||||||
if (picked) {
|
if (picked) {
|
||||||
|
// 2. Find the leaf puppet: the one that contains 'picked' and is not a parent of another that also contains it.
|
||||||
|
// Actually, we can just find all matches and pick the one with most 'nested' prop?
|
||||||
|
// A simpler way: we know 'picked' is the LEAF prop from VTK.
|
||||||
|
// Find a puppet that contains it.
|
||||||
|
Puppet* leafPuppet = nullptr;
|
||||||
for (auto* p : self->m_Puppets) {
|
for (auto* p : self->m_Puppets) {
|
||||||
if (p->GetProp() == picked) {
|
if (containsProp(p->GetProp(), picked)) {
|
||||||
target = p;
|
// If we already have a candidate, check if this one is smaller (nested)
|
||||||
break;
|
if (!leafPuppet || containsProp(leafPuppet->GetProp(), p->GetProp())) {
|
||||||
|
leafPuppet = p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto* propAssembly = vtkPropAssembly::SafeDownCast(p->GetProp());
|
}
|
||||||
auto* actorAssembly = vtkAssembly::SafeDownCast(p->GetProp());
|
|
||||||
vtkPropCollection* parts = nullptr;
|
|
||||||
if (propAssembly) parts = propAssembly->GetParts();
|
|
||||||
else if (actorAssembly) parts = actorAssembly->GetParts();
|
|
||||||
|
|
||||||
if (parts) {
|
if (leafPuppet) {
|
||||||
bool found = false;
|
target = leafPuppet;
|
||||||
parts->InitTraversal();
|
|
||||||
for (int i=0; i<parts->GetNumberOfItems(); ++i) {
|
// 3. Model-driven hierarchy climb:
|
||||||
if (parts->GetNextProp() == picked) {
|
// If the leaf puppet has a uLib object, climb its parents.
|
||||||
found = true;
|
// If any parent is an Assembly with GroupSelection=true, select the assembly puppet instead.
|
||||||
break;
|
uLib::Object* currentObj = leafPuppet->GetContent();
|
||||||
|
|
||||||
|
while (currentObj) {
|
||||||
|
// Object doesn't have parent, but AffineTransform does
|
||||||
|
uLib::Object* parentObj = nullptr;
|
||||||
|
if (auto* at = dynamic_cast<uLib::AffineTransform*>(currentObj)) {
|
||||||
|
parentObj = dynamic_cast<uLib::Object*>(at->GetParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto* parentAsm = dynamic_cast<::uLib::Assembly*>(parentObj)) {
|
||||||
|
if (parentAsm->GetGroupSelection()) {
|
||||||
|
// Find the puppet for this parent assembly
|
||||||
|
auto it = self->m_ObjectToPuppet.find(parentAsm);
|
||||||
|
if (it != self->m_ObjectToPuppet.end()) {
|
||||||
|
target = it->second;
|
||||||
|
// Keep climbing to find even larger groups
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found) {
|
currentObj = parentObj;
|
||||||
target = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,20 +429,74 @@ void Viewport::ZoomSelected()
|
|||||||
|
|
||||||
void Viewport::AddPuppet(Puppet& prop)
|
void Viewport::AddPuppet(Puppet& prop)
|
||||||
{
|
{
|
||||||
m_Puppets.push_back(&prop);
|
this->RegisterPuppet(&prop, false);
|
||||||
prop.ConnectRenderer(pv->m_Renderer);
|
|
||||||
Render();
|
Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RemovePuppet(Puppet& prop)
|
void Viewport::RemovePuppet(Puppet& prop)
|
||||||
{
|
{
|
||||||
if (prop.IsSelected()) SelectPuppet(nullptr);
|
this->UnregisterPuppet(&prop);
|
||||||
auto it = std::find(m_Puppets.begin(), m_Puppets.end(), &prop);
|
|
||||||
if (it != m_Puppets.end()) m_Puppets.erase(it);
|
|
||||||
prop.DisconnectRenderer(pv->m_Renderer);
|
|
||||||
Render();
|
Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewport::RegisterPuppet(Puppet* p, bool isPart) {
|
||||||
|
if (!p) return;
|
||||||
|
if (std::find(m_Puppets.begin(), m_Puppets.end(), p) != m_Puppets.end()) return;
|
||||||
|
|
||||||
|
m_Puppets.push_back(p);
|
||||||
|
p->ConnectRenderer(pv->m_Renderer);
|
||||||
|
|
||||||
|
// If it's a part of an assembly, we don't want to draw it twice.
|
||||||
|
// Assembly itself already draws its parts.
|
||||||
|
// But we need ConnectRenderer above to allow highliting and property updates.
|
||||||
|
if (isPart) {
|
||||||
|
pv->m_Renderer->RemoveViewProp(p->GetProp());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the object and register in map
|
||||||
|
uLib::Object* obj = p->GetContent();
|
||||||
|
|
||||||
|
// If it's an assembly, we need to observe its children
|
||||||
|
if (auto* as = dynamic_cast<::uLib::Vtk::Assembly*>(p)) {
|
||||||
|
this->ObserveContext(as->GetChildrenContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj) m_ObjectToPuppet[obj] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Viewport::UnregisterPuppet(Puppet* p) {
|
||||||
|
if (!p) return;
|
||||||
|
if (p->IsSelected()) SelectPuppet(nullptr);
|
||||||
|
|
||||||
|
auto it = std::find(m_Puppets.begin(), m_Puppets.end(), p);
|
||||||
|
if (it != m_Puppets.end()) m_Puppets.erase(it);
|
||||||
|
|
||||||
|
// Remove from map
|
||||||
|
for (auto mapIt = m_ObjectToPuppet.begin(); mapIt != m_ObjectToPuppet.end(); ) {
|
||||||
|
if (mapIt->second == p) mapIt = m_ObjectToPuppet.erase(mapIt);
|
||||||
|
else ++mapIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->DisconnectRenderer(pv->m_Renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Viewport::ObserveContext(vtkObjectsContext* ctx) {
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
// Process existing puppets
|
||||||
|
for (auto const& [obj, puppet] : ctx->GetPuppets()) {
|
||||||
|
this->RegisterPuppet(puppet, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for future puppets
|
||||||
|
uLib::Object::connect(ctx, &vtkObjectsContext::PuppetAdded, [this](Puppet* p){
|
||||||
|
this->RegisterPuppet(p, true);
|
||||||
|
});
|
||||||
|
uLib::Object::connect(ctx, &vtkObjectsContext::PuppetRemoved, [this](Puppet* p){
|
||||||
|
this->UnregisterPuppet(p);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Viewport::SelectPuppet(Puppet* prop)
|
void Viewport::SelectPuppet(Puppet* prop)
|
||||||
{
|
{
|
||||||
for (auto* p : m_Puppets) {
|
for (auto* p : m_Puppets) {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include "uLibVtkInterface.h"
|
#include "uLibVtkInterface.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace uLib { class Object; }
|
||||||
|
|
||||||
// VTK classes are in the global namespace
|
// VTK classes are in the global namespace
|
||||||
class vtkRenderer;
|
class vtkRenderer;
|
||||||
@@ -74,9 +77,15 @@ protected:
|
|||||||
|
|
||||||
void UpdateGrid();
|
void UpdateGrid();
|
||||||
|
|
||||||
|
// Internal puppet registration
|
||||||
|
void RegisterPuppet(Puppet* p, bool isPart = false);
|
||||||
|
void UnregisterPuppet(Puppet* p);
|
||||||
|
void ObserveContext(class vtkObjectsContext* ctx);
|
||||||
|
|
||||||
struct ViewportData *pv;
|
struct ViewportData *pv;
|
||||||
Axis m_GridAxis;
|
Axis m_GridAxis;
|
||||||
std::vector<Puppet*> m_Puppets;
|
std::vector<Puppet*> m_Puppets;
|
||||||
|
std::map<uLib::Object*, Puppet*> m_ObjectToPuppet;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vtk
|
} // namespace Vtk
|
||||||
|
|||||||
Reference in New Issue
Block a user