fix some on properties and signal connection

This commit is contained in:
AndreaRigoni
2026-03-26 09:50:52 +00:00
parent 2c5d6842c3
commit e0ffeff5b7
22 changed files with 578 additions and 62 deletions

View File

@@ -126,9 +126,11 @@ vtkVoxImage::vtkVoxImage(Content &content)
: m_Content(content), m_Actor(vtkVolume::New()),
m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()),
m_OutlineActor(vtkActor::New()),
m_Reader(NULL), m_Writer(NULL), writer_factor(1.E6) {
m_Reader(NULL), m_Writer(NULL), writer_factor(1.E6),
m_Window(40/1.E6), m_Level(20/1.E6), m_ShadingPreset(0) {
GetContent();
InstallPipe();
ULIB_ACTIVATE_DISPLAY_PROPERTIES;
}
vtkVoxImage::~vtkVoxImage() {
@@ -199,14 +201,15 @@ void vtkVoxImage::ReadFromXMLFile(const char *fname) {
}
void vtkVoxImage::setShadingPreset(int blendType) {
m_ShadingPreset = blendType;
vtkSmartVolumeMapper *mapper = (vtkSmartVolumeMapper *)m_Actor->GetMapper();
vtkVolumeProperty *property = m_Actor->GetProperty();
static vtkColorTransferFunction *colorFun = vtkColorTransferFunction::New();
static vtkPiecewiseFunction *opacityFun = vtkPiecewiseFunction::New();
float window = 40 / writer_factor;
float level = 20 / writer_factor;
float window = m_Window;
float level = m_Level;
property->SetColor(colorFun);
property->SetScalarOpacity(opacityFun);
@@ -281,13 +284,24 @@ void vtkVoxImage::SetRepresentation(Representation mode) {
m_OutlineActor->SetVisibility(1);
} else if (mode == Surface) {
m_Actor->SetVisibility(1);
m_OutlineActor->SetVisibility(0);
m_OutlineActor->SetVisibility(1); // Keep outline visible as boundary
} else {
Puppet::SetRepresentation(mode);
}
}
void vtkVoxImage::serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version) {
// Call base class if it has display properties
Puppet::serialize_display(ar, version);
// Use the member variables if they are available
ar & boost::serialization::make_hrp("Window", m_Window);
ar & boost::serialization::make_hrp("Level", m_Level);
ar & boost::serialization::make_hrp_enum("Shading", m_ShadingPreset, {"MIP", "Composite", "Composite Shaded", "MIP Bone", "MIP Hot", "Additive"});
}
void vtkVoxImage::Update() {
setShadingPreset(m_ShadingPreset);
m_Actor->Update();
m_Outline->SetBounds(m_Image->GetBounds());
m_Outline->Update();

View File

@@ -65,7 +65,8 @@ public:
void setShadingPreset(int blendType = 2);
void SetRepresentation(Representation mode);
void Update();
void Update() override;
void serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version = 0) override;
protected:
void InstallPipe();
@@ -84,6 +85,7 @@ private:
float m_Window;
float m_Level;
int m_ShadingPreset;
};
} // namespace Vtk

View File

@@ -57,6 +57,7 @@
#include <vtkPolyData.h>
#include <vtkFeatureEdges.h>
#include <vtkTransform.h>
#include <vtkRenderWindow.h>
#include "uLibVtkInterface.h"
#include "vtkHandlerWidget.h"
@@ -87,12 +88,17 @@ public:
m_Assembly(vtkSmartPointer<vtkAssembly>::New()),
m_ShowBoundingBox(false),
m_ShowScaleMeasures(false),
m_Representation(-1),
m_Representation(Puppet::Surface),
m_Opacity(-1.0),
m_Selectable(true),
m_Selected(false)
m_Selected(false),
m_Visibility(true),
m_Dragable(true)
{
m_Color[0] = m_Color[1] = m_Color[2] = -1.0;
m_Position[0] = m_Position[1] = m_Position[2] = 0.0;
m_Orientation[0] = m_Orientation[1] = m_Orientation[2] = 0.0;
m_Scale[0] = m_Scale[1] = m_Scale[2] = 1.0;
}
~PuppetData() {
@@ -110,25 +116,49 @@ public:
bool m_ShowBoundingBox;
bool m_ShowScaleMeasures;
int m_Representation;
double m_Color[3];
double m_Opacity;
bool m_Selectable;
bool m_Selected;
bool m_Visibility;
bool m_Dragable;
double m_Position[3];
double m_Orientation[3];
double m_Scale[3];
void ApplyAppearance(vtkProp *p) {
p->SetVisibility(m_Visibility);
p->SetPickable(m_Selectable);
p->SetDragable(m_Dragable);
vtkActor *actor = vtkActor::SafeDownCast(p);
if (!actor) return;
if (actor) {
if (m_Representation != -1) {
if (m_Representation == Puppet::SurfaceWithEdges) {
actor->GetProperty()->SetRepresentation(VTK_SURFACE);
actor->GetProperty()->SetEdgeVisibility(1);
} else {
actor->GetProperty()->SetRepresentation(m_Representation);
actor->GetProperty()->SetEdgeVisibility(0);
}
}
if (m_Color[0] != -1.0) {
actor->GetProperty()->SetColor(m_Color);
}
if (m_Representation != -1) {
actor->GetProperty()->SetRepresentation(m_Representation);
if (m_Opacity != -1.0) {
actor->GetProperty()->SetOpacity(m_Opacity);
}
}
if (m_Color[0] != -1.0) {
actor->GetProperty()->SetColor(m_Color);
}
if (m_Opacity != -1.0) {
actor->GetProperty()->SetOpacity(m_Opacity);
// Handle transformation if it's a Prop3D
if (auto* p3d = vtkProp3D::SafeDownCast(p)) {
// NOTE: Usually managed by Puppet::Update from model, but here for direct prop manipulation
// p3d->SetPosition(m_Position);
// p3d->SetOrientation(m_Orientation);
// p3d->SetScale(m_Scale);
}
}
@@ -188,9 +218,6 @@ public:
}
}
}
bool m_Selectable;
bool m_Selected;
};
// -------------------------------------------------------------------------- //
@@ -226,6 +253,21 @@ void Puppet::SetProp(vtkProp *prop)
pd->m_Assembly->AddPart(p3d);
}
pd->ApplyAppearance(prop);
// For the first actor added, seed the tracked display values from the VTK
// actor's current state so the display properties panel shows meaningful
// initial values instead of the -1 "not-overriding" sentinels.
if (pd->m_Assembly->GetParts()->GetNumberOfItems() == 1) {
if (auto* actor = vtkActor::SafeDownCast(prop)) {
vtkProperty* vp = actor->GetProperty();
if (pd->m_Representation < 0)
pd->m_Representation = vp->GetRepresentation();
if (pd->m_Opacity < 0)
pd->m_Opacity = vp->GetOpacity();
if (pd->m_Color[0] < 0)
vp->GetColor(pd->m_Color);
}
}
}
}
@@ -370,13 +412,7 @@ void Puppet::ShowScaleMeasures(bool show)
void Puppet::SetRepresentation(Representation mode)
{
int rep = VTK_SURFACE;
switch (mode) {
case Points: rep = VTK_POINTS; break;
case Wireframe: rep = VTK_WIREFRAME; break;
case Surface: rep = VTK_SURFACE; break;
}
pd->m_Representation = rep;
pd->m_Representation = static_cast<int>(mode);
vtkProp3DCollection *props = pd->m_Assembly->GetParts();
props->InitTraversal();
@@ -391,6 +427,10 @@ void Puppet::SetRepresentation(const char *mode)
if (s == "points") SetRepresentation(Points);
else if (s == "wireframe") SetRepresentation(Wireframe);
else if (s == "shaded" || s == "surface") SetRepresentation(Surface);
else if (s == "edges" || s == "surface+edges" || s == "surfacewithedges") SetRepresentation(SurfaceWithEdges);
else if (s == "volume") SetRepresentation(Volume);
else if (s == "outline") SetRepresentation(Outline);
else if (s == "slice") SetRepresentation(Slice);
}
void Puppet::SetColor(double r, double g, double b)
@@ -453,6 +493,18 @@ bool Puppet::IsSelected() const
void Puppet::Update()
{
vtkProp* root = this->GetProp();
if (root) {
pd->ApplyAppearance(root);
// Apply transformation if it's a Prop3D
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
p3d->SetPosition(pd->m_Position);
p3d->SetOrientation(pd->m_Orientation);
p3d->SetScale(pd->m_Scale);
}
}
vtkProp3DCollection *props = pd->m_Assembly->GetParts();
props->InitTraversal();
for (int i = 0; i < props->GetNumberOfItems(); ++i) {
@@ -473,6 +525,42 @@ void Puppet::Update()
double* bounds = pd->m_Assembly->GetBounds();
pd->m_CubeAxesActor->SetBounds(bounds);
}
// Notify that the object has been updated (important for UI refresh)
this->Object::Updated();
// Trigger immediate re-render of all connected viewports
pd->m_Renderers->InitTraversal();
for (int i = 0; i < pd->m_Renderers->GetNumberOfItems(); ++i) {
if (auto* ren = pd->m_Renderers->GetNextItem()) {
if (ren->GetRenderWindow()) ren->GetRenderWindow()->Render();
}
}
}
void Puppet::SyncFromVtk()
{
vtkProp* root = this->GetProp();
if (auto* p3d = vtkProp3D::SafeDownCast(root)) {
double pos[3], ori[3], scale[3];
p3d->GetPosition(pos);
p3d->GetOrientation(ori);
p3d->GetScale(scale);
// Update properties
for (int i=0; i<3; ++i) {
pd->m_Position[i] = pos[i];
pd->m_Orientation[i] = ori[i];
pd->m_Scale[i] = scale[i];
}
// Get the properties from the object
if (auto* propPos = this->GetProperty("Position")) propPos->Updated();
if (auto* propOri = this->GetProperty("Orientation")) propOri->Updated();
if (auto* propScale = this->GetProperty("Scale")) propScale->Updated();
this->Object::Updated();
}
}
void Puppet::ConnectInteractor(vtkRenderWindowInteractor *interactor)
@@ -484,7 +572,21 @@ void Puppet::serialize_display(Archive::display_properties_archive & ar, const u
ar & boost::serialization::make_hrp("ColorG", pd->m_Color[1]);
ar & boost::serialization::make_hrp("ColorB", pd->m_Color[2]);
ar & boost::serialization::make_hrp("Opacity", pd->m_Opacity);
ar & boost::serialization::make_hrp("Representation", pd->m_Representation);
ar & boost::serialization::make_hrp_enum("Representation", pd->m_Representation, {"Points", "Wireframe", "Surface", "SurfaceWithEdges", "Volume", "Outline", "Slice"});
ar & boost::serialization::make_hrp("Visibility", pd->m_Visibility);
ar & boost::serialization::make_hrp("Pickable", pd->m_Selectable);
ar & boost::serialization::make_hrp("Dragable", pd->m_Dragable);
// Geometry knobs (caution: these might be overridden by internal matrices)
ar & boost::serialization::make_hrp("PosX", pd->m_Position[0], "mm");
ar & boost::serialization::make_hrp("PosY", pd->m_Position[1], "mm");
ar & boost::serialization::make_hrp("PosZ", pd->m_Position[2], "mm");
ar & boost::serialization::make_hrp("OriX", pd->m_Orientation[0], "deg");
ar & boost::serialization::make_hrp("OriY", pd->m_Orientation[1], "deg");
ar & boost::serialization::make_hrp("OriZ", pd->m_Orientation[2], "deg");
ar & boost::serialization::make_hrp("ScaleX", pd->m_Scale[0]);
ar & boost::serialization::make_hrp("ScaleY", pd->m_Scale[1]);
ar & boost::serialization::make_hrp("ScaleZ", pd->m_Scale[2]);
}
void Puppet::serialize(Archive::xml_oarchive & ar, const unsigned int v) { }

View File

@@ -82,8 +82,9 @@ public:
bool IsSelected() const;
virtual void Update();
virtual void SyncFromVtk();
enum Representation { Points, Wireframe, Surface };
enum Representation { Points = 0, Wireframe = 1, Surface = 2, SurfaceWithEdges = 3, Volume = 4, Outline = 5, Slice = 6 };
void SetRepresentation(Representation mode);
void SetRepresentation(const char *mode);
@@ -131,6 +132,17 @@ private:
} // namespace Vtk
} // namespace uLib
// -------------------------------------------------------------------------- //
// DISPLAY PROPERTIES SERIALIZE
// -------------------------------------------------------------------------- //
namespace uLib {
@@ -148,9 +160,20 @@ public:
template<class T>
void save_override(const boost::serialization::hrp<T> &t) {
if (m_Puppet) {
m_Puppet->RegisterDisplayProperty(
new uLib::Property<T>(m_Puppet, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value())
);
uLib::Property<T>* p = new uLib::Property<T>(m_Puppet, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value(), t.units() ? t.units() : "");
m_Puppet->RegisterDisplayProperty(p);
Vtk::Puppet* puppet = m_Puppet;
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
}
}
template<class T>
void save_override(const boost::serialization::hrp_enum<T> &t) {
if (m_Puppet) {
uLib::EnumProperty* p = new uLib::EnumProperty(m_Puppet, t.name(), (int*)&const_cast<boost::serialization::hrp_enum<T>&>(t).value(), t.labels(), t.units() ? t.units() : "");
m_Puppet->RegisterDisplayProperty(p);
Vtk::Puppet* puppet = m_Puppet;
uLib::Object::connect(p, &uLib::PropertyBase::Updated, [puppet](){ puppet->Update(); });
}
}

View File

@@ -2,6 +2,7 @@
#include "Vtk/Math/vtkContainerBox.h"
#include "Vtk/Math/vtkCylinder.h"
#include "Vtk/Math/vtkAssembly.h"
#include "Vtk/Math/vtkVoxImage.h"
#include "HEP/Detectors/vtkDetectorChamber.h"
#include <vtkAssembly.h>
@@ -116,6 +117,8 @@ Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) {
return new vtkDetectorChamber(static_cast<uLib::DetectorChamber*>(obj));
} else if (std::strcmp(className, "Cylinder") == 0) {
return new vtkCylinder(static_cast<uLib::Cylinder*>(obj));
} else if (std::strcmp(className, "VoxImage") == 0) {
return new vtkVoxImage(*static_cast<uLib::Abstract::VoxImage*>(obj));
} else if (std::strcmp(className, "Assembly") == 0) {
return new Assembly(static_cast<uLib::Assembly*>(obj));
}

View File

@@ -101,6 +101,11 @@ void QViewport::onGridButtonClicked()
SetGridVisible(m_GridButton->isChecked());
}
void QViewport::OnSelectionChanged(Puppet* p)
{
emit puppetSelected(p);
}
void QViewport::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);

View File

@@ -30,6 +30,8 @@ namespace Vtk {
*/
class QViewport : public QWidget, public Viewport {
Q_OBJECT
signals:
void puppetSelected(uLib::Vtk::Puppet* p);
public:
explicit QViewport(QWidget* parent = nullptr);
virtual ~QViewport();
@@ -42,6 +44,8 @@ public:
virtual vtkRenderWindowInteractor* GetInteractor() override;
QVTKOpenGLNativeWidget* GetWidget() { return m_VtkWidget; }
virtual void OnSelectionChanged(Puppet* p) override;
protected:
virtual void resizeEvent(QResizeEvent* event) override;

View File

@@ -208,6 +208,7 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren)
auto* self = static_cast<Viewport*>(clientdata);
for (auto* p : self->m_Puppets) {
if (p->IsSelected()) {
p->SyncFromVtk();
p->Update();
}
}
@@ -518,6 +519,7 @@ void Viewport::SelectPuppet(Puppet* prop)
}
Render();
OnSelectionChanged(prop);
}
void Viewport::SetGridVisible(bool visible)

View File

@@ -62,6 +62,7 @@ public:
vtkCornerAnnotation* GetAnnotation();
vtkCameraOrientationWidget* GetCameraWidget();
void DisableHandler();
virtual void OnSelectionChanged(Puppet* p) {}
const std::vector<Puppet*>& getPuppets() const { return m_Puppets; }
// Grid control