You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmRender/nmVTKOrientationMarkerContr...

264 lines
8.4 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmVTKOrientationMarkerController.h"
#include <QCoreApplication>
#include <QThread>
#include <vtkAxesActor.h>
#include <vtkCaptionActor2D.h>
#include <vtkMath.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTextProperty.h>
namespace {
// OrientationMarkerWidget 会维护观察关系和辅助 Renderer只能在 GUI 线程操作。
bool isOrientationMarkerGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == nullptr ||
pApplication->thread() == QThread::currentThread();
}
// 同时设置轴杆、箭头和标签颜色,避免依赖不同 VTK 版本的默认外观。
void setAxisColor(vtkProperty* pShaftProperty,
vtkProperty* pTipProperty,
vtkCaptionActor2D* pCaptionActor,
double dRed,
double dGreen,
double dBlue)
{
if(pShaftProperty != nullptr) {
pShaftProperty->SetColor(dRed, dGreen, dBlue);
}
if(pTipProperty != nullptr) {
pTipProperty->SetColor(dRed, dGreen, dBlue);
}
if(pCaptionActor != nullptr &&
pCaptionActor->GetCaptionTextProperty() != nullptr) {
pCaptionActor->GetCaptionTextProperty()->SetColor(
dRed, dGreen, dBlue);
}
}
}
nmVTKOrientationMarkerController::nmVTKOrientationMarkerController()
: m_pAxesActor(vtkSmartPointer<vtkAxesActor>::New()),
m_pMarkerWidget(
vtkSmartPointer<vtkOrientationMarkerWidget>::New()),
m_pInteractor(nullptr),
m_pRenderer(nullptr),
m_bVisible(true),
m_bViewAvailable(false)
{
Q_ASSERT(isOrientationMarkerGuiThread());
m_dViewport[0] = 0.015;
m_dViewport[1] = 0.015;
m_dViewport[2] = 0.13;
m_dViewport[3] = 0.13;
if(m_pAxesActor != nullptr) {
m_pAxesActor->SetXAxisLabelText("X");
m_pAxesActor->SetYAxisLabelText("Y");
m_pAxesActor->SetZAxisLabelText("Z");
setAxisColor(m_pAxesActor->GetXAxisShaftProperty(),
m_pAxesActor->GetXAxisTipProperty(),
m_pAxesActor->GetXAxisCaptionActor2D(),
1.0, 0.0, 0.0);
setAxisColor(m_pAxesActor->GetYAxisShaftProperty(),
m_pAxesActor->GetYAxisTipProperty(),
m_pAxesActor->GetYAxisCaptionActor2D(),
0.0, 1.0, 0.0);
setAxisColor(m_pAxesActor->GetZAxisShaftProperty(),
m_pAxesActor->GetZAxisTipProperty(),
m_pAxesActor->GetZAxisCaptionActor2D(),
0.0, 0.0, 1.0);
}
if(m_pMarkerWidget != nullptr) {
// 构造阶段尚未绑定 Interactor只关闭键盘入口并保存默认视口。
m_pMarkerWidget->KeyPressActivationOff();
m_pMarkerWidget->SetViewport(m_dViewport);
}
}
nmVTKOrientationMarkerController::~nmVTKOrientationMarkerController()
{
Q_ASSERT(isOrientationMarkerGuiThread());
unbindInteractor();
m_pMarkerWidget = nullptr;
m_pAxesActor = nullptr;
}
bool nmVTKOrientationMarkerController::bindInteractor(
vtkRenderWindowInteractor* pInteractor,
vtkRenderer* pRenderer)
{
Q_ASSERT(isOrientationMarkerGuiThread());
if(!isOrientationMarkerGuiThread()) {
return false;
}
// 每次绑定都从干净状态开始,避免 Widget 保留旧窗口的观察关系。
unbindInteractor();
vtkRenderWindow* pRenderWindow = pInteractor != nullptr ?
pInteractor->GetRenderWindow() : nullptr;
if(pInteractor == nullptr || pRenderer == nullptr ||
pRenderWindow == nullptr || pRenderer->GetRenderWindow() != pRenderWindow ||
m_pAxesActor == nullptr || m_pMarkerWidget == nullptr) {
return false;
}
m_pInteractor = pInteractor;
m_pRenderer = pRenderer;
// 显式指定主 Renderer不能依赖鼠标位置推断多 Renderer 窗口的父相机。
m_pMarkerWidget->SetOrientationMarker(m_pAxesActor);
m_pMarkerWidget->SetDefaultRenderer(m_pRenderer);
m_pMarkerWidget->SetCurrentRenderer(m_pRenderer);
m_pMarkerWidget->SetInteractor(m_pInteractor);
updateEnabledState();
bool bBindingValid =
m_pMarkerWidget->GetInteractor() == m_pInteractor &&
m_pMarkerWidget->GetDefaultRenderer() == m_pRenderer &&
m_pMarkerWidget->GetOrientationMarker() ==
m_pAxesActor.GetPointer();
if(bBindingValid && m_bVisible && m_bViewAvailable) {
bBindingValid = m_pMarkerWidget->GetEnabled() != 0 &&
m_pMarkerWidget->GetInteractive() == 0 &&
m_pMarkerWidget->GetCurrentRenderer() == m_pRenderer;
}
if(!bBindingValid) {
unbindInteractor();
return false;
}
return true;
}
void nmVTKOrientationMarkerController::unbindInteractor()
{
Q_ASSERT(isOrientationMarkerGuiThread());
if(!isOrientationMarkerGuiThread()) {
return;
}
if(m_pMarkerWidget == nullptr) {
m_pInteractor = nullptr;
m_pRenderer = nullptr;
return;
}
// 只有已绑定且实际启用时才禁用,重复解绑不会触发 VTK 状态警告。
if(m_pMarkerWidget->GetInteractor() != nullptr &&
m_pMarkerWidget->GetEnabled() != 0) {
m_pMarkerWidget->SetEnabled(0);
}
// 完整解绑会释放 Widget 持有的 Actor、Renderer 和 Interactor 引用。
m_pMarkerWidget->SetOrientationMarker(nullptr);
m_pMarkerWidget->SetDefaultRenderer(nullptr);
m_pMarkerWidget->SetCurrentRenderer(nullptr);
m_pMarkerWidget->SetInteractor(nullptr);
m_pInteractor = nullptr;
m_pRenderer = nullptr;
}
void nmVTKOrientationMarkerController::setVisible(bool bVisible)
{
Q_ASSERT(isOrientationMarkerGuiThread());
if(!isOrientationMarkerGuiThread()) {
return;
}
m_bVisible = bVisible;
updateEnabledState();
}
bool nmVTKOrientationMarkerController::isVisible() const
{
return m_bVisible;
}
void nmVTKOrientationMarkerController::setViewAvailable(bool bAvailable)
{
Q_ASSERT(isOrientationMarkerGuiThread());
if(!isOrientationMarkerGuiThread()) {
return;
}
m_bViewAvailable = bAvailable;
updateEnabledState();
}
bool nmVTKOrientationMarkerController::isViewAvailable() const
{
return m_bViewAvailable;
}
bool nmVTKOrientationMarkerController::setViewport(
double dXMinimum,
double dYMinimum,
double dXMaximum,
double dYMaximum)
{
Q_ASSERT(isOrientationMarkerGuiThread());
if(!isOrientationMarkerGuiThread() ||
!vtkMath::IsFinite(dXMinimum) ||
!vtkMath::IsFinite(dYMinimum) ||
!vtkMath::IsFinite(dXMaximum) ||
!vtkMath::IsFinite(dYMaximum) ||
dXMinimum < 0.0 || dYMinimum < 0.0 ||
dXMaximum > 1.0 || dYMaximum > 1.0 ||
dXMaximum <= dXMinimum || dYMaximum <= dYMinimum ||
m_pMarkerWidget == nullptr) {
return false;
}
m_dViewport[0] = dXMinimum;
m_dViewport[1] = dYMinimum;
m_dViewport[2] = dXMaximum;
m_dViewport[3] = dYMaximum;
m_pMarkerWidget->SetViewport(m_dViewport);
return true;
}
void nmVTKOrientationMarkerController::updateEnabledState()
{
if(m_pMarkerWidget == nullptr) {
return;
}
const bool bShouldEnable = m_pAxesActor != nullptr &&
m_pInteractor != nullptr &&
m_pRenderer != nullptr &&
m_pMarkerWidget->GetInteractor() == m_pInteractor &&
m_pMarkerWidget->GetDefaultRenderer() == m_pRenderer &&
m_pMarkerWidget->GetOrientationMarker() ==
m_pAxesActor.GetPointer() &&
m_bVisible && m_bViewAvailable;
if(bShouldEnable) {
// VTK 7.1 禁用 Widget 后会清空 CurrentRenderer恢复前必须重新指定。
m_pMarkerWidget->SetCurrentRenderer(m_pRenderer);
m_pMarkerWidget->SetEnabled(1);
if(m_pMarkerWidget->GetEnabled() != 0 &&
m_pMarkerWidget->GetInteractive() != 0) {
// Interactive 只有在首次成功启用后设置才会被 VTK 正确接受。
m_pMarkerWidget->SetInteractive(0);
}
return;
}
// 临时隐藏只禁用 Widget保留 Marker、Interactor 和默认 Renderer 绑定。
if(m_pMarkerWidget->GetInteractor() != nullptr &&
m_pMarkerWidget->GetEnabled() != 0) {
m_pMarkerWidget->SetEnabled(0);
}
}