727 lines
23 KiB
C++
727 lines
23 KiB
C++
/*//////////////////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
|
|
#if VTK_MAJOR_VERSION <= 5
|
|
#
|
|
#else
|
|
# include <vtkAutoInit.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
|
|
#include <string>
|
|
#include <vtkVersion.h>
|
|
#include "vtkViewport.h"
|
|
#include "uLibVtkInterface.h"
|
|
#include "Math/Transform.h"
|
|
#include <vtkActor.h>
|
|
#include <vtkPolyDataMapper.h>
|
|
#include <vtkProperty.h>
|
|
#include <vtkPropCollection.h>
|
|
#include <vtkProp3DCollection.h>
|
|
#include <vtkRendererCollection.h>
|
|
#include <vtkAssembly.h>
|
|
#include <vtkOutlineSource.h>
|
|
#include <vtkPolyDataMapper.h>
|
|
#include <vtkCubeAxesActor.h>
|
|
#include <vtkRenderer.h>
|
|
#include <vtkProperty.h>
|
|
#include <vtkCamera.h>
|
|
#include <vtkPolyData.h>
|
|
#include <vtkFeatureEdges.h>
|
|
#include <vtkTransform.h>
|
|
#include <vtkCubeSource.h>
|
|
#include <vtkRenderWindow.h>
|
|
|
|
#include "uLibVtkInterface.h"
|
|
#include "vtkHandlerWidget.h"
|
|
#include "Vtk/Math/vtkDense.h"
|
|
#include "Vtk/Math/vtkDense.h"
|
|
#include "Core/Property.h"
|
|
#include "Math/Transform.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace uLib {
|
|
namespace Vtk {
|
|
|
|
|
|
// PIMPL -------------------------------------------------------------------- //
|
|
|
|
class Prop3DData {
|
|
public:
|
|
Prop3DData(Prop3D* owner) :
|
|
m_Prop3D(owner),
|
|
m_Renderers(vtkSmartPointer<vtkRendererCollection>::New()),
|
|
m_Prop(nullptr),
|
|
m_ShowBoundingBox(false),
|
|
m_ShowScaleMeasures(false),
|
|
m_Representation(Prop3D::Surface),
|
|
m_Opacity(1.0),
|
|
m_Selectable(true),
|
|
m_Selected(false),
|
|
m_Visibility(true),
|
|
m_Dragable(true),
|
|
m_HighlightMode(Prop3D::HighlightPlain)
|
|
{
|
|
m_Color = Vector3d(-1, -1, -1);
|
|
}
|
|
|
|
~Prop3DData() {
|
|
// No manual Delete needed for smart pointers
|
|
|
|
}
|
|
|
|
Prop3D *m_Prop3D;
|
|
// members //
|
|
vtkSmartPointer<vtkRendererCollection> m_Renderers;
|
|
vtkSmartPointer<vtkProp3D> m_Prop;
|
|
|
|
vtkSmartPointer<vtkOutlineSource> m_OutlineSource;
|
|
vtkSmartPointer<vtkActor> m_OutlineActor;
|
|
vtkSmartPointer<vtkCubeAxesActor> m_CubeAxesActor;
|
|
vtkSmartPointer<vtkActor> m_HighlightActor;
|
|
|
|
// Display properties
|
|
bool m_ShowBoundingBox;
|
|
bool m_ShowScaleMeasures;
|
|
int m_Representation; // 0: Points, 1: Wireframe, 2: Surface, 3: SurfaceWithEdges, 4: Volume, 5: Outline, 6: Slice
|
|
Vector3d m_Color;
|
|
double m_Opacity;
|
|
|
|
bool m_Selectable;
|
|
bool m_Selected;
|
|
bool m_Visibility;
|
|
bool m_Dragable;
|
|
|
|
int m_HighlightMode; // 0: Plain, 1: Corners
|
|
|
|
//
|
|
TRS m_Transform;
|
|
|
|
void ApplyAppearance(vtkProp *p) {
|
|
if (!p) return;
|
|
p->SetVisibility(m_Visibility);
|
|
p->SetPickable(m_Selectable);
|
|
p->SetDragable(m_Dragable);
|
|
|
|
vtkActor *actor = vtkActor::SafeDownCast(p);
|
|
if (actor) {
|
|
if (m_Representation != -1 && m_Representation != Prop3D::Volume) {
|
|
if (m_Representation == Prop3D::SurfaceWithEdges) {
|
|
actor->GetProperty()->SetRepresentation(VTK_SURFACE);
|
|
actor->GetProperty()->SetEdgeVisibility(1);
|
|
} else if (m_Representation != Prop3D::Outline && m_Representation != Prop3D::Slice) {
|
|
actor->GetProperty()->SetRepresentation(m_Representation);
|
|
actor->GetProperty()->SetEdgeVisibility(0);
|
|
}
|
|
}
|
|
if (m_Color.x() != -1.0) {
|
|
double c[3] = {m_Color.x(), m_Color.y(), m_Color.z()};
|
|
actor->GetProperty()->SetColor(c);
|
|
}
|
|
|
|
if (m_Opacity != -1.0) {
|
|
actor->GetProperty()->SetOpacity(m_Opacity);
|
|
}
|
|
} else if (vtkAssembly *asm_p = vtkAssembly::SafeDownCast(p)) {
|
|
// Recursively apply to parts of the assembly
|
|
vtkProp3DCollection *parts = asm_p->GetParts();
|
|
if (parts) {
|
|
parts->InitTraversal();
|
|
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
|
|
this->ApplyAppearance(parts->GetNextProp3D());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ApplyTransform(vtkProp3D* p3d) {
|
|
if (p3d) {
|
|
p3d->SetUserMatrix(nullptr);
|
|
p3d->SetPosition(m_Transform.position.x(), m_Transform.position.y(), m_Transform.position.z());
|
|
|
|
// Convert Model Radians to VTK Degrees
|
|
p3d->SetOrientation(m_Transform.rotation.x() / CLHEP::degree,
|
|
m_Transform.rotation.y() / CLHEP::degree,
|
|
m_Transform.rotation.z() / CLHEP::degree);
|
|
|
|
p3d->SetScale(m_Transform.scaling.x(), m_Transform.scaling.y(), m_Transform.scaling.z());
|
|
}
|
|
}
|
|
|
|
void UpdateHighlight() {
|
|
if (m_Selected) {
|
|
vtkPolyData* polydata = nullptr;
|
|
if (vtkActor *actor = vtkActor::SafeDownCast(m_Prop)) {
|
|
if (actor->GetMapper()) {
|
|
polydata = vtkPolyData::SafeDownCast(actor->GetMapper()->GetInput());
|
|
}
|
|
} else if (vtkAssembly *asm_p = vtkAssembly::SafeDownCast(m_Prop)) {
|
|
vtkPropCollection *parts = asm_p->GetParts();
|
|
if (parts) {
|
|
parts->InitTraversal();
|
|
for (int i = 0; i < parts->GetNumberOfItems(); ++i) {
|
|
vtkActor *a = vtkActor::SafeDownCast(parts->GetNextProp());
|
|
if (a && a->GetMapper()) {
|
|
polydata = vtkPolyData::SafeDownCast(a->GetMapper()->GetInput());
|
|
if (polydata) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!polydata) {
|
|
if (m_HighlightActor) {
|
|
m_Renderers->InitTraversal();
|
|
for (int i = 0; i < m_Renderers->GetNumberOfItems(); ++i) {
|
|
m_Renderers->GetNextItem()->RemoveActor(m_HighlightActor);
|
|
}
|
|
m_HighlightActor = nullptr;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!m_HighlightActor) {
|
|
m_HighlightActor = vtkSmartPointer<vtkActor>::New();
|
|
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
|
m_HighlightActor->SetMapper(mapper);
|
|
m_HighlightActor->GetProperty()->SetRepresentationToWireframe();
|
|
m_HighlightActor->GetProperty()->SetColor(1.0, 0.0, 0.0); // Red
|
|
m_HighlightActor->GetProperty()->SetLineWidth(2.0);
|
|
m_HighlightActor->GetProperty()->SetLighting(0);
|
|
}
|
|
|
|
if (m_HighlightMode == Prop3D::HighlightPlain) {
|
|
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
|
|
double bounds[6];
|
|
polydata->GetBounds(bounds);
|
|
double maxDim = std::max({bounds[1]-bounds[0], bounds[3]-bounds[2], bounds[5]-bounds[4]});
|
|
double pad = maxDim * 0.02;
|
|
if(pad < 1e-4) pad = 0.05;
|
|
cube->SetBounds(bounds[0]-pad, bounds[1]+pad,
|
|
bounds[2]-pad, bounds[3]+pad,
|
|
bounds[4]-pad, bounds[5]+pad);
|
|
cube->Update();
|
|
m_HighlightActor->GetMapper()->SetInputConnection(cube->GetOutputPort());
|
|
} else {
|
|
// Corners mode logic
|
|
double bounds[6];
|
|
polydata->GetBounds(bounds);
|
|
double maxDim = std::max({bounds[1]-bounds[0], bounds[3]-bounds[2], bounds[5]-bounds[4]});
|
|
double pad = maxDim * 0.02;
|
|
if(pad < 1e-4) pad = 0.05;
|
|
|
|
double b[6] = {bounds[0]-pad, bounds[1]+pad, bounds[2]-pad, bounds[3]+pad, bounds[4]-pad, bounds[5]+pad};
|
|
|
|
vtkNew<vtkPoints> points;
|
|
vtkNew<vtkCellArray> lines;
|
|
|
|
float len[3] = {
|
|
(float)(b[1] - b[0]) * 0.15f,
|
|
(float)(b[3] - b[2]) * 0.15f,
|
|
(float)(b[5] - b[4]) * 0.15f
|
|
};
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
double p[3];
|
|
p[0] = b[(i & 1) ? 1 : 0];
|
|
p[1] = b[(i & 2) ? 1 : 0];
|
|
p[2] = b[(i & 4) ? 1 : 0];
|
|
|
|
for (int axis = 0; axis < 3; ++axis) {
|
|
double p2[3] = {p[0], p[1], p[2]};
|
|
double 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> cornerPoly;
|
|
cornerPoly->SetPoints(points);
|
|
cornerPoly->SetLines(lines);
|
|
if (auto* mapper = vtkPolyDataMapper::SafeDownCast(m_HighlightActor->GetMapper())) {
|
|
mapper->SetInputData(cornerPoly);
|
|
}
|
|
}
|
|
|
|
// Update highlight matrix from the model world matrix
|
|
if (m_Prop3D) {
|
|
if (auto* content = m_Prop3D->GetContent()) {
|
|
if (auto* tr = dynamic_cast<uLib::TRS*>(content)) {
|
|
vtkNew<vtkMatrix4x4> vwm;
|
|
Matrix4fToVtk(tr->GetWorldMatrix(), vwm);
|
|
m_HighlightActor->SetUserMatrix(vwm);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_Renderers->InitTraversal();
|
|
for (int i = 0; i < m_Renderers->GetNumberOfItems(); ++i) {
|
|
vtkRenderer *ren = m_Renderers->GetNextItem();
|
|
ren->AddActor(m_HighlightActor);
|
|
}
|
|
} else {
|
|
if (m_HighlightActor) {
|
|
m_Renderers->InitTraversal();
|
|
for (int i = 0; i < m_Renderers->GetNumberOfItems(); ++i) {
|
|
m_Renderers->GetNextItem()->RemoveActor(m_HighlightActor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Prop3D::Prop3D() : Object(), pd(new Prop3DData(this)) {
|
|
ULIB_ACTIVATE_DISPLAY_PROPERTIES;
|
|
}
|
|
|
|
Prop3D::~Prop3D()
|
|
{
|
|
delete pd;
|
|
}
|
|
|
|
vtkProp *Prop3D::GetProp()
|
|
{
|
|
return pd->m_Prop;
|
|
}
|
|
|
|
vtkProp3D *Prop3D::GetProxyProp()
|
|
{
|
|
// The handler should manipulate the highlight actor if it exists
|
|
if (pd->m_HighlightActor) {
|
|
return pd->m_HighlightActor;
|
|
}
|
|
return vtkProp3D::SafeDownCast(this->GetProp());
|
|
}
|
|
|
|
void Prop3D::SetProp(vtkProp *prop)
|
|
{
|
|
if(prop) {
|
|
prop->SetPickable(pd->m_Selectable);
|
|
pd->m_Prop = vtkProp3D::SafeDownCast(prop);
|
|
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 (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.x() < 0) {
|
|
double c[3];
|
|
vp->GetColor(c);
|
|
pd->m_Color = Vector3d(c[0], c[1], c[2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::RemoveProp(vtkProp *prop)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void Prop3D::ApplyAppearance(vtkProp* prop)
|
|
{
|
|
pd->ApplyAppearance(prop);
|
|
}
|
|
|
|
void Prop3D::ApplyTransform(vtkProp3D* p3d)
|
|
{
|
|
pd->ApplyTransform(p3d);
|
|
}
|
|
|
|
|
|
vtkPropCollection *Prop3D::GetParts()
|
|
{
|
|
if (auto* asm_p = vtkAssembly::SafeDownCast(pd->m_Prop)) {
|
|
return asm_p->GetParts();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
vtkPropCollection *Prop3D::GetProps()
|
|
{
|
|
if (auto* asm_p = vtkAssembly::SafeDownCast(pd->m_Prop)) {
|
|
return asm_p->GetParts();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Prop3D::ConnectRenderer(vtkRenderer *renderer)
|
|
{
|
|
if(renderer) {
|
|
this->GetRenderers()->AddItem(renderer);
|
|
if(vtkProp* prop = this->GetProp()) {
|
|
renderer->AddViewProp(prop);
|
|
}
|
|
|
|
if (pd->m_ShowBoundingBox && pd->m_OutlineActor) renderer->AddActor(pd->m_OutlineActor);
|
|
if (pd->m_ShowScaleMeasures && pd->m_CubeAxesActor) {
|
|
pd->m_CubeAxesActor->SetCamera(renderer->GetActiveCamera());
|
|
renderer->AddActor(pd->m_CubeAxesActor);
|
|
}
|
|
|
|
if (pd->m_Selected && pd->m_HighlightActor) {
|
|
renderer->AddActor(pd->m_HighlightActor);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::DisconnectRenderer(vtkRenderer *renderer)
|
|
{
|
|
if(renderer) {
|
|
if(vtkProp* prop = this->GetProp())
|
|
renderer->RemoveViewProp(prop);
|
|
|
|
if (pd->m_ShowBoundingBox && pd->m_OutlineActor) renderer->RemoveActor(pd->m_OutlineActor);
|
|
if (pd->m_ShowScaleMeasures && pd->m_CubeAxesActor) renderer->RemoveActor(pd->m_CubeAxesActor);
|
|
|
|
this->GetRenderers()->RemoveItem(renderer);
|
|
}
|
|
}
|
|
|
|
void Prop3D::AddToViewer(Viewport &viewer)
|
|
{
|
|
viewer.AddProp3D(*this);
|
|
}
|
|
|
|
void Prop3D::RemoveFromViewer(Viewport &viewer)
|
|
{
|
|
viewer.RemoveProp3D(*this);
|
|
}
|
|
|
|
vtkRendererCollection *Prop3D::GetRenderers() const
|
|
{
|
|
return pd->m_Renderers;
|
|
}
|
|
|
|
void Prop3D::PrintSelf(std::ostream &o) const
|
|
{
|
|
o << "Props Assembly: \n";
|
|
if (pd->m_Prop)
|
|
pd->m_Prop->PrintSelf(o,vtkIndent(1));
|
|
|
|
o << "Connected Renderers: \n";
|
|
pd->m_Renderers->PrintSelf(o,vtkIndent(1));
|
|
}
|
|
|
|
void Prop3D::ShowBoundingBox(bool show)
|
|
{
|
|
if (pd->m_ShowBoundingBox == show) return;
|
|
pd->m_ShowBoundingBox = show;
|
|
if (show) {
|
|
if (!pd->m_OutlineActor) {
|
|
pd->m_OutlineSource = vtkSmartPointer<vtkOutlineSource>::New();
|
|
pd->m_OutlineActor = vtkSmartPointer<vtkActor>::New();
|
|
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
|
mapper->SetInputConnection(pd->m_OutlineSource->GetOutputPort());
|
|
pd->m_OutlineActor->SetMapper(mapper);
|
|
pd->m_OutlineActor->GetProperty()->SetColor(1.0, 1.0, 1.0);
|
|
}
|
|
|
|
if (pd->m_Prop) {
|
|
double* bounds = pd->m_Prop->GetBounds();
|
|
pd->m_OutlineSource->SetBounds(bounds);
|
|
pd->m_OutlineSource->Update();
|
|
}
|
|
|
|
pd->m_Renderers->InitTraversal();
|
|
for (int i = 0; i < pd->m_Renderers->GetNumberOfItems(); ++i) {
|
|
vtkRenderer *renderer = pd->m_Renderers->GetNextItem();
|
|
renderer->AddActor(pd->m_OutlineActor);
|
|
}
|
|
} else {
|
|
if (pd->m_OutlineActor) {
|
|
pd->m_Renderers->InitTraversal();
|
|
for (int i = 0; i < pd->m_Renderers->GetNumberOfItems(); ++i) {
|
|
vtkRenderer *renderer = pd->m_Renderers->GetNextItem();
|
|
renderer->RemoveActor(pd->m_OutlineActor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::ShowScaleMeasures(bool show)
|
|
{
|
|
if (pd->m_ShowScaleMeasures == show) return;
|
|
pd->m_ShowScaleMeasures = show;
|
|
if (show) {
|
|
if (!pd->m_CubeAxesActor) {
|
|
pd->m_CubeAxesActor = vtkSmartPointer<vtkCubeAxesActor>::New();
|
|
pd->m_CubeAxesActor->SetFlyModeToOuterEdges();
|
|
pd->m_CubeAxesActor->SetUseTextActor3D(1);
|
|
pd->m_CubeAxesActor->GetProperty()->SetColor(1.0, 1.0, 1.0);
|
|
}
|
|
|
|
if (pd->m_Prop) {
|
|
double* bounds = pd->m_Prop->GetBounds();
|
|
pd->m_CubeAxesActor->SetBounds(bounds);
|
|
}
|
|
|
|
pd->m_Renderers->InitTraversal();
|
|
for (int i = 0; i < pd->m_Renderers->GetNumberOfItems(); ++i) {
|
|
vtkRenderer *renderer = pd->m_Renderers->GetNextItem();
|
|
pd->m_CubeAxesActor->SetCamera(renderer->GetActiveCamera());
|
|
renderer->AddActor(pd->m_CubeAxesActor);
|
|
}
|
|
} else {
|
|
if (pd->m_CubeAxesActor) {
|
|
pd->m_Renderers->InitTraversal();
|
|
for (int i = 0; i < pd->m_Renderers->GetNumberOfItems(); ++i) {
|
|
vtkRenderer *renderer = pd->m_Renderers->GetNextItem();
|
|
renderer->RemoveActor(pd->m_CubeAxesActor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::SetRepresentation(Representation mode)
|
|
{
|
|
pd->m_Representation = static_cast<int>(mode);
|
|
pd->ApplyAppearance(pd->m_Prop);
|
|
}
|
|
|
|
void Prop3D::SetRepresentation(const char *mode)
|
|
{
|
|
std::string s(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 Prop3D::SetHighlightMode(HighlightMode mode)
|
|
{
|
|
pd->m_HighlightMode = static_cast<int>(mode);
|
|
pd->UpdateHighlight();
|
|
}
|
|
|
|
void Prop3D::SetColor(double r, double g, double b)
|
|
{
|
|
pd->m_Color[0] = r;
|
|
pd->m_Color[1] = g;
|
|
pd->m_Color[2] = b;
|
|
pd->ApplyAppearance(pd->m_Prop);
|
|
}
|
|
|
|
void Prop3D::SetOpacity(double alpha)
|
|
{
|
|
pd->m_Opacity = alpha;
|
|
pd->ApplyAppearance(pd->m_Prop);
|
|
}
|
|
|
|
void Prop3D::GetColor(double &r, double &g, double &b) const
|
|
{
|
|
r = pd->m_Color[0];
|
|
g = pd->m_Color[1];
|
|
b = pd->m_Color[2];
|
|
}
|
|
|
|
double Prop3D::GetOpacity() const
|
|
{
|
|
return pd->m_Opacity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Prop3D::SetSelectable(bool selectable)
|
|
{
|
|
pd->m_Selectable = selectable;
|
|
pd->ApplyAppearance(pd->m_Prop);
|
|
}
|
|
|
|
bool Prop3D::IsSelectable() const
|
|
{
|
|
return pd->m_Selectable;
|
|
}
|
|
|
|
void Prop3D::SetSelected(bool selected)
|
|
{
|
|
if (!pd->m_Selectable) return;
|
|
if (pd->m_Selected == selected) return;
|
|
pd->m_Selected = selected;
|
|
pd->UpdateHighlight();
|
|
}
|
|
|
|
bool Prop3D::IsSelected() const
|
|
{
|
|
return pd->m_Selected;
|
|
}
|
|
|
|
void Prop3D::ApplyProp3DTransform(vtkProp3D* prop)
|
|
{
|
|
if (!prop) return;
|
|
if (auto* content = this->GetContent()) {
|
|
if (auto* tr = dynamic_cast<uLib::TRS*>(content)) {
|
|
vtkNew<vtkMatrix4x4> m;
|
|
Matrix4fToVtk(tr->GetMatrix(), m);
|
|
prop->SetUserMatrix(m);
|
|
prop->Modified();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::SyncFromVtk()
|
|
{
|
|
if (auto* content = this->GetContent()) {
|
|
if (auto* tr = dynamic_cast<uLib::TRS*>(content)) {
|
|
if (auto* proxy = this->GetProxyProp()) {
|
|
if (vtkMatrix4x4* mat = proxy->GetUserMatrix()) {
|
|
tr->FromMatrix(VtkToMatrix4f(mat));
|
|
content->Updated();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Prop3D::Update()
|
|
{
|
|
// Apply content transform via virtual GetProp() / ApplyProp3DTransform(),
|
|
// so all derived classes benefit without duplicating the matrix code.
|
|
this->ApplyProp3DTransform(vtkProp3D::SafeDownCast(this->GetProp()));
|
|
|
|
// Use virtual GetProp() for appearance so overriders (e.g. VoxImage)
|
|
// that never call SetProp() are handled correctly.
|
|
pd->ApplyAppearance(this->GetProp());
|
|
|
|
if (pd->m_Selected) {
|
|
pd->UpdateHighlight();
|
|
}
|
|
|
|
if (auto* prop = this->GetProp()) {
|
|
if (pd->m_ShowBoundingBox && pd->m_OutlineSource) {
|
|
double* bounds = prop->GetBounds();
|
|
pd->m_OutlineSource->SetBounds(bounds);
|
|
pd->m_OutlineSource->Update();
|
|
}
|
|
if (pd->m_ShowScaleMeasures && pd->m_CubeAxesActor) {
|
|
pd->m_CubeAxesActor->SetBounds(prop->GetBounds());
|
|
}
|
|
}
|
|
|
|
// 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 Prop3D::ConnectInteractor(vtkRenderWindowInteractor *interactor)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------ //
|
|
// SERIALIZE DISPLAY PROPERTIES
|
|
|
|
|
|
struct TransformProxy {
|
|
Prop3DData* pd;
|
|
template<class Archive>
|
|
void serialize(Archive & ar, const unsigned int version) {
|
|
ar & boost::serialization::make_nvp("Transform", pd->m_Transform);
|
|
}
|
|
};
|
|
|
|
struct AppearanceProxy {
|
|
Prop3DData* pd;
|
|
template<class Archive>
|
|
void serialize(Archive & ar, const unsigned int version) {
|
|
ar & boost::serialization::make_hrp("Color", pd->m_Color, "color");
|
|
ar & boost::serialization::make_hrp("Opacity", pd->m_Opacity).range(0.0, 1.0).set_default(1.0);
|
|
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);
|
|
ar & boost::serialization::make_hrp("ShowBoundingBox", pd->m_ShowBoundingBox);
|
|
ar & boost::serialization::make_hrp("ShowScaleMeasures", pd->m_ShowScaleMeasures);
|
|
ar & boost::serialization::make_hrp_enum("HighlightMode",
|
|
pd->m_HighlightMode, {"Plain", "Corners"});
|
|
}
|
|
};
|
|
|
|
void Prop3D::serialize_display(Archive::display_properties_archive & ar, const unsigned int version) {
|
|
AppearanceProxy appearance{pd};
|
|
ar & boost::serialization::make_nvp("Appearance", appearance);
|
|
|
|
TransformProxy transform{pd};
|
|
ar & boost::serialization::make_nvp("Transform", transform);
|
|
}
|
|
|
|
|
|
} // namespace Vtk
|
|
} // namespace uLib
|