#include "nmVTKOrientationMarkerController.h" #include #include #include #include #include #include #include #include #include #include #include namespace { // OrientationMarkerWidget 会维护观察关系和辅助 Renderer,只能在 GUI 线程操作。 bool isOrientationMarkerGuiThread() { QCoreApplication* pApplication = QCoreApplication::instance(); return pApplication == nullptr || pApplication->thread() == QThread::currentThread(); } // 方向轴杆和箭头使用各自的方向色,标签颜色由独立函数统一设置。 void setAxisColor(vtkProperty* pShaftProperty, vtkProperty* pTipProperty, double dRed, double dGreen, double dBlue) { if(pShaftProperty != nullptr) { pShaftProperty->SetColor(dRed, dGreen, dBlue); } if(pTipProperty != nullptr) { pTipProperty->SetColor(dRed, dGreen, dBlue); } } void setCaptionColor(vtkCaptionActor2D* pCaptionActor, double dRed, double dGreen, double dBlue) { if(pCaptionActor != nullptr && pCaptionActor->GetCaptionTextProperty() != nullptr) { pCaptionActor->GetCaptionTextProperty()->SetColor( dRed, dGreen, dBlue); } } } nmVTKOrientationMarkerController::nmVTKOrientationMarkerController() : m_pAxesActor(vtkSmartPointer::New()), m_pMarkerWidget( vtkSmartPointer::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(), 1.0, 0.0, 0.0); setAxisColor(m_pAxesActor->GetYAxisShaftProperty(), m_pAxesActor->GetYAxisTipProperty(), 0.0, 1.0, 0.0); setAxisColor(m_pAxesActor->GetZAxisShaftProperty(), m_pAxesActor->GetZAxisTipProperty(), 0.0, 0.0, 1.0); setCaptionColor(m_pAxesActor->GetXAxisCaptionActor2D(), 1.0, 1.0, 1.0); setCaptionColor(m_pAxesActor->GetYAxisCaptionActor2D(), 1.0, 1.0, 1.0); setCaptionColor(m_pAxesActor->GetZAxisCaptionActor2D(), 1.0, 1.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); } }